Tuesday, August 25, 2015

Digest for comp.lang.c++@googlegroups.com - 19 updates in 4 topics

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 25 01:17AM +0100

On Mon, 24 Aug 2015 17:13:46 -0500
 
> So you cannot return a boost::thread from a method?
> I am not sure why not? Why can't we?
> It seems to work if I change it to return a pointer...
 
Pointers are built in types and always copiable.
 
However, your design is wrong. You attempt to export the thread
class member object of SomeClass by copying it - the reason given in the
comments being: "Return the thread we started, so that the caller may
wait on it to join along with any other threads the started from other
instances of this class."
 
This shows that you have got your ownership semantics wrong,
presumably to get around the rule (with POSIX threads and which
probably therefore applies to boost threads) that you cannot have two
different threads joining on the same thread object: the SUS states
that "the results of multiple simultaneous calls to pthread_join()
specifying the same target thread are undefined". However, your
copying doesn't work because thread objects are not copyable (copying is
semantically meaningless and impossible to achieve with POSIX threads
and probably also windows threads); and returning a pointer won't work
because it subverts your original intention of making a copy to avoid
violating the aforementioned requirement. Usually, if you want multiple
threads to wait for a condition such as thread termination you need to
use a condition variable.
 
(Although you do not use C++ threads, the same rule that applies
to POSIX threads appears to apply to std::thread, because it is a
precondition of calling join() that the thread should be joinable(),
and a thread ceases to be joinable as soon as join() or detach() returns
in a thread: this is not surprising because the standard states, albeit
non-normatively, that "These threads [std::thread threads] are intended
to map one-to-one with operating system threads".)
 
More generally, your approach seems like an unnecessarily convoluted way
of starting a thread.
 
Chris
Christopher Pisz <nospam@notanaddress.com>: Aug 25 10:30AM -0500

On 8/24/2015 7:17 PM, Chris Vine wrote:
> different threads joining on the same thread object: the SUS states
> that "the results of multiple simultaneous calls to pthread_join()
> specifying the same target thread are undefined".
 
I don't understand the why behind it being semantically wrong. I am not
trying have more than one thread in which the joins are called. I am
trying to join all the child threads in the main thread.
 
> copying doesn't work because thread objects are not copyable (copying is
> semantically meaningless and impossible to achieve with POSIX threads
> and probably also windows threads);
 
I am not trying to "create a new thread by copying the thread object. I
am trying to "pass some thing the main thread can use to join on"
 
> and returning a pointer won't work
> because it subverts your original intention of making a copy to avoid
> violating the aforementioned requirement.
 
But it does work in my test. I'll post my edited concept code at the bottom.
 
> Usually, if you want multiple
> threads to wait for a condition such as thread termination you need to
> use a condition variable.
 
Just the main thread.
 
> (Although you do not use C++ threads, the same rule that applies
> to POSIX threads appears to apply to std::thread, because it is a
> precondition of calling join() that the thread should be joinable(),
 
It should be
 
 
> More generally, your approach seems like an unnecessarily convoluted way
> of starting a thread.
 
> Chris
 
Maybe so. Garnering suggestions on how to edit it are my goal, but I
have a feeling people are misinterpreting what I am trying to do. I just
want to start multiple threads from one parent thread and have that
parent wait on them all to terminate, unless an signal is obtained, in
which case I want the main thread to signal the child threads to
terminate. I am trying to also encapsulate all the
activity/functionality that takes place on the child threads, in a
class. Maybe this concept code does a better job of it:
 
________
#pragma once
 
// Boost Includes
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
 
// Standard Includes
#include <atomic>
 
//--------------------------------------------------------------------------------------------------
class SomeClass
{
public:
 
typedef boost::shared_ptr<SomeClass> Shared_Ptr;
 
static void Start(SomeClass & someClass);
 
SomeClass();
~SomeClass();
 
void Stop();
void Join();
 
protected:
 
void ThreadProcedure();
 
static size_t m_count;
size_t m_id;
boost::thread m_thread; // Worker thread this
object will run on
boost::function<void()> m_threadProcedure; // Function object that
is the main loop for the thread
std::atomic<bool> m_stopping; // Flag to exit loop in
thread
};
 
__________
 
 
#include "SomeClass.h"
 
// Boost Includes
#include <boost/thread.hpp>
 
// Standard Includes
#include <iostream>
 
//--------------------------------------------------------------------------------------------------
size_t SomeClass::m_count = 0;
 
//--------------------------------------------------------------------------------------------------
void SomeClass::Start(SomeClass & someClass)
{
// Start the thread
someClass.m_thread.swap(boost::thread(someClass.m_threadProcedure));
}
 
//--------------------------------------------------------------------------------------------------
void SomeClass::Stop()
{
// Flags the loop in the thread procedure to exit
m_stopping = true;
}
 
//--------------------------------------------------------------------------------------------------
void SomeClass::Join()
{
m_thread.join();
}
 
//--------------------------------------------------------------------------------------------------
SomeClass::SomeClass()
:
m_id (m_count++),
m_thread (),
// Derived classes should override this behavior by binding their
own thread procedure in their constructor
m_threadProcedure(boost::bind(&SomeClass::ThreadProcedure, this)),
m_stopping (false)
{
std::cout << "SomeClass #" << m_id << " constructor has been
called." << std::endl;
}
 
//--------------------------------------------------------------------------------------------------
SomeClass::~SomeClass()
{
std::cout << "SomeClass #" << m_id << " deconstructor has been
called." << std::endl;
 
// If the thread is still running, interupt it and wait for it to join
m_thread.interrupt();
m_thread.join();
}
 
//--------------------------------------------------------------------------------------------------
void SomeClass::ThreadProcedure()
{
std::cout << "SomeClass #" << m_id << " thread procedure has been
called." << std::endl;
 
// Will go forever until interupted
try
{
while(!m_stopping.load())
{
boost::this_thread::sleep_for(boost::chrono::seconds(60));
std::cout << "SomeClass #" << m_id << " tick..." << std::endl;
}
}
catch(boost::thread_interrupted)
{
std::cout << "SomeClass #" << m_id << " interupted. Exiting
thread." << std::endl;
}
 
std::cout << "SomeClass #" << m_id << " stopped. Exiting thread."
<< std::endl;
 
}
 
____________
 
// Project Includes
#include "SomeClass.h"
 
// Shared Library
#include "Exception.h"
#include "PerformanceTimer.h"
 
// Boost Includes
#include <boost/thread/thread.hpp>
 
// Standard Library
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
 
#include <signal.h>
 
//--------------------------------------------------------------------------------------------------
// TODO - Only global for concept testing, later we'll wrap all this in
a class
std::vector<SomeClass::Shared_Ptr> g_workerObjects;
 
//--------------------------------------------------------------------------------------------------
void SignalHandler(int signal)
{
// Signal worker thread to exit
std::cout << "Halt signal caught. Exiting all threads..." << std::endl;
 
for(std::vector<SomeClass::Shared_Ptr>::const_iterator itWorker =
g_workerObjects.begin(); itWorker != g_workerObjects.end(); ++itWorker)
{
(*itWorker)->Stop();
}
}
 
//--------------------------------------------------------------------------------------------------
int main()
{
// Register a handler for the ctrl-z signal
signal(SIGINT, SignalHandler);
 
// Create the workers and start thier threads
for(size_t index = 0; index < 10; ++index)
{
SomeClass::Shared_Ptr worker(new SomeClass());
SomeClass::Start(*worker);
g_workerObjects.push_back(worker);
}
 
// Wait for the threads to exit
std::vector<SomeClass::Shared_Ptr>::const_iterator itWorker =
g_workerObjects.begin();
 
while(itWorker != g_workerObjects.end())
{
(*itWorker)->Join();
itWorker = g_workerObjects.erase(itWorker);
}
 
// Done
return 0;
}
 
 
 
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
scott@slp53.sl.home (Scott Lurndal): Aug 25 06:16PM

>> threads to wait for a condition such as thread termination you need to
>> use a condition variable.
 
>Just the main thread.
 
My generic (pthread-based) thread class has the following
method that handles the join.
 
When the destructor for the class that inherits from c_thread
is called, the thread will be joined.
 
bool in_context(void) { return t_thread == pthread_self(); }
 
 
/*
* Terminate the thread. If called in-context, it will clear the
* running flag and exit. If called out of context, it will cancel
* the thread and join with it.
*/
void
c_thread::terminate(void)
{
int diag;
 
if (in_context()) {
t_running = false;
pthread_exit(NULL);
} else {
diag = pthread_cancel(t_thread);
if (diag == ESRCH) {
/* Thread already gone, nothing to do */
} else if (diag != 0) {
t_logger->log("%s Unable to cancel thread: %s\n",
t_thread_name, strerror(diag));
}
 
void *rval;
diag = pthread_join(t_thread, &rval);
if (diag == ESRCH) {
/* Thread already gone, nothing to do */
} else if (diag != 0) {
t_logger->log("%s Thread join failed: %s\n",
t_thread_name, strerror(diag));
}
t_running = false;
}
}
 
 
A class that needs a thread will inherit from c_thread and will
implement the virtual c_thread::run() method for the body of the
thread.
 
An example ::run method:
 
/**
* SSP Thread. This thread will coordinate ownership of a lock between
* the hosts which are connected to the SSP instance.
*/
void
c_ssp::run(void)
{
 
s_lock.lock();
s_running = true;
while (s_running) {
s_wait_for_work.wait(&s_lock);
 
if (!s_running) continue;
 
while (s_file->sf_waiter[s_sysnum].sf_waitlist != SSP_TABLE_SIZE) {
s_lock_notify *lnp = s_file->sf_notifiers;
 
lnp += s_file->sf_waiter[s_sysnum].sf_waitlist;
s_file->sf_waiter[s_sysnum].sf_waitlist = lnp->ln_offset;
 
c_dlist_iterator di (&s_lock_list);
while (di.next()) {
s_lock_op *lop = (s_lock_op *)di.curr();
 
if (lop->lo_address == lnp->ln_address) {
lop->remove();
s_client->lock_acquired(lop->lo_handle, false);
delete lop;
lnp->ln_offset = s_file->sf_freelist;
s_file->sf_freelist = lnp->ln_this;
}
}
}
}
s_terminate_wait.signal();
s_lock.unlock();
}
 
 
 
/**
* Destroy an SSP implementation.
*/
c_ssp::~c_ssp(void)
{
s_lock.lock();
s_running = false; // Signal ::run method to terminate
s_wait_for_work.signal(); // Awaken ::run method
s_terminate_wait.wait(&s_lock); // Wait for ::run method to exit
terminate(); // Join with thread
 
if (s_file != NULL) {
munmap(s_file, SSP_MAILBOX_SIZE);
s_file = NULL;
}
s_lock.unlock();
}
 
s_running member data item is declared volatile, of course.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 25 09:34PM +0100

On Tue, 25 Aug 2015 10:30:14 -0500
Christopher Pisz <nospam@notanaddress.com> wrote:
[snip]
> > to POSIX threads appears to apply to std::thread, because it is a
> > precondition of calling join() that the thread should be joinable(),
 
> It should be
 
Not in your usage (see below). A thread ceases to be joinable as soon
as detach() is called on it, or otherwise at some unspecified time after
the thread has terminated between a call to join() being made and that
call returning. See in particular §30.3.1.5/2 and §30.3.1.5/6 of C++11.
 
[snip]
> threads to terminate. I am trying to also encapsulate all the
> activity/functionality that takes place on the child threads, in a
> class. Maybe this concept code does a better job of it:
 
OK I can see where you are going. Having a thread handle (which is
basically what SomeClass now is) is not a bad idea, given that
std::thread is not exception safe for a joinable thread (but
boost::thread is). Having protected data members would also normally
be regarded as unusual, but presumably it is to make your m_stopping
flag visible to a worker thread function provided by a derived class,
but in that case I cannot see the point of having the polymorphic
function object m_threadProcedure - you might just as well use
inheritance with a virtual thread function, much as I try to avoid
them except for type erasure purposes.
 
However, on the technical level you still have undefined behaviour.
I mentioned that you cannot have more than one thread joining on
another according to the C++ and POSIX standards (and, having looked at
the boost documentation, I see also according to boost). In your code
the destructor of SomeClass calls join() on m_thread and any thread
calling your SomeClass::Join() method will do the same. By the time the
destructor of SomeClass is entered and calls join() any thread blocking
on SomeClass::join() will probably have returned leaving the thread in
already detached state and the destructor with undefined behaviour.
You say "But it does work in my test". If having non-conforming code
which happens to work on a particular compiler version with a
particular OS version is enough for the purposes of the contract with
your clients, so be it. If you are concerned with portability and
standard compliance you would use a condition variable, or remove your
SomeClass::Join() function.
 
(As an aside, you will get away with it on any implementation where
std::vector iterators are pointers, but manipulating iterators in a
signal handler is technically undefined behaviour because no standard
library functions are guaranteed to be asynchronous-safe except loads
and stores on lock-free atomic objects - §1.9/6 of C++11.
std::atomic<bool> is going to be lock free in practice. You might as
well use relaxed memory ordering for that usage though.)
 
Chris
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Aug 25 09:59PM +0100

On Tue, 25 Aug 2015 21:34:56 +0100
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> wrote:
[snip]
> signal handler is technically undefined behaviour because no standard
> library functions are guaranteed to be asynchronous-safe except loads
> and stores on lock-free atomic objects - §1.9/6 of C++11.
 
Actually, because your main() function and your signal handler both
manipulate g_workerObjects, in your test case you will only get away
with it if the thread in which the signal handler runs is the thread in
which main() runs. To do that you would need to block signals in all
but the main thread using sigprocmask()/pthread_sigmask() or whatever
equivalent your OS offers. Otherwise you would need a mutex to protect
g_workerObjects, and mutexes are definitely not asynchronous safe.
 
In multi-threaded code I always use sigwait() to deal with asynchronous
signals safely.
 
Chris
"Öö Tiib" <ootiib@hot.ee>: Aug 24 05:50PM -0700

On Monday, 24 August 2015 15:27:58 UTC+3, David Brown wrote:
> small difference. For example, if a function bar() contains a call to
> an external function foo(), the code generated for bar() must take into
> account the possibility that foo() throws an exception.
 
Exceptions are expensive only when used wrongly to signal about quite
common situations. If foo() throws exceptions, but rarely, (lets say
once from 20000 calls) then exception is actually measurably cheaper
(and also results with cleaner code) than to check return values and
propagate those up stack. It is because exception is cheaper than return
value checking in good case situation.
 
One issue with exception is when stack unwinding takes unacceptably
long time but we we need both to succeed and to fail fast. It is rare
case, some critical real time processing for example. For fixing that
we can still use return values in C++ like we anyway do with
non-exceptional edge cases.
 
> This can mean
> different requirements for stack layout or restrictions to optimisations
> and re-organisations that would not apply in the case of plain C.
 
That only applies when we are sure that there can't be any exceptional
failures. If foo() can not throw exceptions then we have to declare
foo() 'noexcept' in C++ to gain same benefit.
 
> could have been written better or faster using C++ rather than C.
 
> (I haven't tried look at this in detail myself - maybe I will do so if I
> get the time.)
 
For whatever braindead reasons even the destructors and extern "C"
functions are not made 'noexcept' by default. One could indicate with
'noexcept(false)' if there really is throwing destructor or extern "C"
function but standard is backward there. IOW we have to use 'noexcept'
massively if we want to get really rid of that one percent as well.
Richard Damon <Richard@Damon-Family.org>: Aug 24 10:19PM -0400

On 8/24/15 8:50 PM, Öö Tiib wrote:
 
> 'noexcept(false)' if there really is throwing destructor or extern "C"
> function but standard is backward there. IOW we have to use 'noexcept'
> massively if we want to get really rid of that one percent as well.
 
The issue is that there is nothing in the language to say that
destructors or extern "C" functions naturally can't throw.
 
We normally try not to have destructors throw, as a destructor throwings
in the midst of processing another exception can cause problems.
 
extern "C" functions may well be written in C++ or call C++ functions
which might throw, so we can't presume them not to throw.
 
The biggest issue is that the first version of C++ defaulted to anything
could throw (and I think it would be a mistake to require all functions
that might throw to indicate this), backwards compatibility make it hard
to change that default.
"Öö Tiib" <ootiib@hot.ee>: Aug 25 12:07AM -0700

On Tuesday, 25 August 2015 05:19:25 UTC+3, Richard Damon wrote:
> > massively if we want to get really rid of that one percent as well.
 
> The issue is that there is nothing in the language to say that
> destructors or extern "C" functions naturally can't throw.
 
There are no things natural. Like that members or bases of class
(but not struct) are private by default. Why not protected?
Because standard say private, nothing inherently natural. Authors
thought that in such a way it is more convenient. So the question
only is: what is more convenient default 'noexcept(false)' or
'noexcept(true)'? I would say that for destructors and extern "C"
functions the more natural default is 'noexcept(true)' for all the
rest 'noexcept(false)'.
 
> We normally try not to have destructors throw, as a destructor throwings
> in the midst of processing another exception can cause problems.
 
So normal and usual (IOW default) is 'noexcept(true)'?

> extern "C" functions may well be written in C++ or call C++ functions
> which might throw, so we can't presume them not to throw.
 
However the normal and usual (IOW default) is 'noexcept(true)'?
 
> could throw (and I think it would be a mistake to require all functions
> that might throw to indicate this), backwards compatibility make it hard
> to change that default.
 
On such obvious cases it is the bad of backwards guys if they miss
an unit test that checks the test case where their throwing destructor
or extern "C" function does actually throw. It is typically causing
nuisance if someone throws C++ exceptions over C interface or out of
destructor so if it really is intended then it should be explicitly
marked that way as well IMHO.
Juha Nieminen <nospam@thanks.invalid>: Aug 25 08:16AM

> number of structs, it is typical to have another struct as a "vtable".
 
> then you would access it as:
> obj->vt->Whatever(obj, ...);
 
And then they say that C is "faster" than C++...
 
(Sure, that resembles virtual functions in C++, but a) in C++ you are
not forced to have every member function being virtual, which means
that the compiler elides the indirection, and may even be able to
inline the function, and b) even with virtual functions the compiler
may be able to perform optimizations that it can't do with an explicit
"virtual table" like that.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
jacobnavia <jacob@jacob.remcomp.fr>: Aug 25 10:28AM +0200

Le 24/08/2015 14:27, Juha Nieminen a écrit :
> This requirement is "inherited" by anything that uses such data containers.
> For example, if you put such a data container in a struct, the struct
> automatically "inherits" the need for manual construction and destruction.
 
Yes, you have to call the destructors explicitely. It is done using
 
container.Finalize // release all memory and the container itself
container.Clear // release all memory and reset the container
 
 
> With complex data structures, it can become really complicated to track
> which structs require manual construction and destruction, and which don't.
 
It is very simple. When you are finished with a container you should
call its Finalize method.
 
> And we all know how error-prone (and tedious) non-RAII manual destruction
> can be. It's one of the biggest sources of bugs in C programs out there.
 
Yes but this is the price to pay to avoid C++ complexity that is also a
source of many bugs.
 
> some dynamic data structure, and you need to create another dynamic
> data structure containing elements of that struct type.) The data
> structure needs to know how to destroy those elements appropriately.
 
No. Data is always copied into the container and the container manages
its own data space so you just have to call its Finalize/Clear method.
Tere are NO shared data between containers.
 
> The classical way of doing that is to add "member functions" to structs
> for construction and destruction... as function pointers. Which increase
> the size of the struct, thus adding overhead.
 
No. The way it is done in the CCL is that you have a SINGLE function
pointer table (the *interface* object for each container) and you call
the functions in there. Note that you can at any moment substitute the
given functions by your own.
 
> they are not virtual. Even if they are virtual, the penalty is that
> of one single pointer regardless of the number of virtual member
> functions.)
 
In the CCL too. No size penalty for your structures that do NOT store
any pointers at all.
 
 
> And debugging macro-based dynamic data containers must be a joy.
 
It is. The source code is available and easy to debug. No templates, no
problems debugging template code. It is funny how you ignore the
difficulty of debugging any STL container or even JUST UNDERSTANDING the
error messages whe necessary.
 
For instance here is an example of the C macros used:
 
102 static int Sort(VECTOR_TYPE *AL)
103 {
104 CompareInfo ci;
105
106 if (AL == NULL) {
107 return NullPtrError("Sort");
108 }
109 ci.ContainerLeft = AL;
110 ci.ExtraArgs = NULL;
111 qsortEx(AL->contents, AL->count, AL->ElementSize,
AL->CompareFn, &ci);
112 return 1;
113 }
 
The only generic argument is the type name of the elements stored in the
vector: "VECTOR_TYPE".
 
Is this too much for you?
jacobnavia <jacob@jacob.remcomp.fr>: Aug 25 10:31AM +0200

Le 25/08/2015 10:16, Juha Nieminen a écrit :
 
>> then you would access it as:
>> obj->vt->Whatever(obj, ...);
 
> And then they say that C is "faster" than C++...
 
It is.
 
> not forced to have every member function being virtual, which means
> that the compiler elides the indirection, and may even be able to
> inline the function,
 
Of course the C compilers could do exactly the same, nothing prevents a
C compiler for doing that optimization. They do not do it now because
there is not much usage in C for that.
 
The first C++ compilers did not have that optimization either.
 
and b) even with virtual functions the compiler
> may be able to perform optimizations that it can't do with an explicit
> "virtual table" like that.)
 
The C compilers could do that too.
Ian Collins <ian-news@hotmail.com>: Aug 25 08:36PM +1200

jacobnavia wrote:
> problems debugging template code. It is funny how you ignore the
> difficulty of debugging any STL container or even JUST UNDERSTANDING the
> error messages whe necessary.
 
There is no problem debugging template code, it's just code. If you
want to avoid cryptic error messages, use a compiler other than gcc :)
 
--
Ian Collins
David Brown <david.brown@hesbynett.no>: Aug 25 11:09AM +0200

On 25/08/15 02:50, Öö Tiib wrote:
> (and also results with cleaner code) than to check return values and
> propagate those up stack. It is because exception is cheaper than return
> value checking in good case situation.
 
That's all true. You can think of the exception and catching as being a
bit like checking for error return values, but heavily optimised for the
"no error" case. This makes exceptions faster than traditional C-style
error checking.
 
My point here is in comparison to /no/ error checking - because you know
there won't be an error, or because you don't care about what happens if
there is an error. In this case, the code generated for C++ that runs
when there is no exception may not be as optimal as if the compiler knew
that no exception could possibly happen.
 
 
> That only applies when we are sure that there can't be any exceptional
> failures. If foo() can not throw exceptions then we have to declare
> foo() 'noexcept' in C++ to gain same benefit.
 
Yes, using "noexcept" should (I think) give these benefits. But you
would have to use it extensively, and AFAIUI it can cause overhead in
functions that are declared "noexcept" (since they have to check if
there are exceptions in functions that they call, and then call
std::terminate()).
 
> 'noexcept(false)' if there really is throwing destructor or extern "C"
> function but standard is backward there. IOW we have to use 'noexcept'
> massively if we want to get really rid of that one percent as well.
 
I have read that destructors are implicitly "noexcept" in C++11, but I
can't say I follow all the details:
 
<https://akrzemi1.wordpress.com/2013/08/20/noexcept-destructors/>
 
 
The trouble with extern "C" functions being default "noexcept" is that
C++ code can call a C function which calls a C++ function which throws -
the exception should make its way back. For an extern "C" function to
be "noexcept", you have to be sure that any unhandled exceptions result
in an std::terminate() - and that will not be the case for all extern
"C" functions.
Thomas Richter <thor@math.tu-berlin.de>: Aug 25 04:07PM +0200

On 25.08.2015 15:50, Stefan Ram wrote:
 
> I have little experience with this.
 
> When can I use the »noexcept« specification and not
> be lying to the implementation?
 
Whenever it is acceptable that a thrown exception terminates the program.
 
> In my C++ course, at the beginning, I use
 
> - arithmetic operators, can they throw?
 
If these are arithmetic operators on the built-in types, then no.
 
 
> - »::std::cout << ...«, can this throw?
 
Well. Here we already have something like a corner case. No, they don't
throw on I/O exceptions because std::cio predates exceptions, so a
different mechanism is used to indicate I/O errors.
 
*However* it does not sound too implausible that these functions are
library implementations that, as part of the implementation, use the
global new operator in one place or another, and *this* operator can throw.
 
I wish C++ would be more clear which library functions can throw which
exception, *including* errors from memory allocation.
 
I'm also unclear whether a C++ library is required to mark functions as
noexcept if it can guarantee that they are noexcept. Probably not.
 
> . Another approach would be to mark /every/ function
> »noexcept« in some programs, /even if/ it can throw.
 
This is usually a bad idea as makes any exception processing impossible.
 
> If I read 15.4p10 correctly, the worst thing that can
> happen is that »::std::unexpected()« or »::std::terminate()«
 
Actually, the latter, not the former. The former happens if an exception
tries to propagate outside of a function marked as throw() (which is
deprecated).
 
> But if the exception in this case still /is/ "handled"
> in this sense, will it really be faster with the
> »noexcept« specification?
 
That I cannot answer. One of the reasons for deprecating throw() was
that it was essentially equivalent to
 
try {
... function body ...
} catch() {
std::unexpected();
}
 
so the compiler had to generate *more* code to process throw() instead
of less code, so it is usually of no advantage (speed-wise) to mark a
function as throw(). And what can you actually do in std:unexpected()
except printing an error and terminating the program anyhow?
 
Why that changes if std::unexpected() is replaced by std::terminate(),
as it happens if throw() is replaced by noexcept, is another question.
Probably because it does not require the compiler to unwind the stack,
i.e. the program may terminate right away. Whether that is any better I
do not know.
 
Actually, I believe that it might have probably been better just to say
that noexcept might have caused UB in case an exception tries to
propagate out of such a function, including behavior such as "works and
just propagates the exception", "does not destroy objects on the stack"
to "just crashes". It would be closer to the "you do not need to pay
what you do not need" approach C++ typically takes in such cases.
 
Greetings,
Thomas
BGB <cr88192@hotmail.com>: Aug 25 09:14AM -0500

On 8/25/2015 3:16 AM, Juha Nieminen wrote:
> inline the function, and b) even with virtual functions the compiler
> may be able to perform optimizations that it can't do with an explicit
> "virtual table" like that.)
 
the non-virtual case is:
Foo_Whatever(obj, ...);
 
however, what one may note though, is that if an indirect call from a
certain location tends to always land on the same target, then the CPU
catches this case and makes it a bit faster.
 
otherwise, one is still faced with a similar cost for pretty much every
call for targets which use ELF (pretty much every non-inline call
tending to be implemented as an indirect call through the GOT).
"Öö Tiib" <ootiib@hot.ee>: Aug 25 11:49AM -0700

On Tuesday, 25 August 2015 12:09:29 UTC+3, David Brown wrote:
> functions that are declared "noexcept" (since they have to check if
> there are exceptions in functions that they call, and then call
> std::terminate()).
 
That check is most likely made by implementation of 'throw' not
by functions. We assume that 'throw' can't happen. If it happens
then it finds a noexcept function in stack and says "Phew, lucky me!
I do not need to unwind anything today. :) Terminate!".
 
 
> I have read that destructors are implicitly "noexcept" in C++11, but I
> can't say I follow all the details:
 
> <https://akrzemi1.wordpress.com/2013/08/20/noexcept-destructors/>
 
You are correct! I was wrong. Opposite behavior is bug in old version
of gcc that I had to use recently and it has been fixed since gcc 4.8.
So on conforming compiler the destructors are already 'noexcept(true)'
and I can take back that part of my complaint.
 
> be "noexcept", you have to be sure that any unhandled exceptions result
> in an std::terminate() - and that will not be the case for all extern
> "C" functions.
 
I have heard that example before but it does not make sense to me.
C function should be capable of calling only extern "C" functions.
If such are 'nothrow(true)' then how those can throw into C?
 
If C code is somehow calling 'nothrow(false)' function and that throws
then C++ exception crosses language boundaries and that is undefined
behavior AFAIK. C function does have no ways to release (or close or
unlock) any resources it acquired since it knows nothing of C++
exceptions. If the exception passes it somehow and further is even
caught by C++ that called the C function then we have alive nasal
daemons instead of 'std::terminate'.
David Brown <david.brown@hesbynett.no>: Aug 25 09:32PM +0200

On 25/08/15 20:49, 嘱 Tiib wrote:
> exceptions. If the exception passes it somehow and further is even
> caught by C++ that called the C function then we have alive nasal
> daemons instead of 'std::terminate'.
 
This is getting /way/ outside my level of C++ (I don't actually do much
C++ at the moment, and when I do it is mostly on embedded systems - and
exceptions are disabled entirely). But my understanding is that an
extern "C" function is not treated any differently with regard to
exceptions - the function can throw, and it can pass on thrown
exceptions down the chain. The extern "C" merely means there is no name
mangling (thus no overloading or default parameters), and may
conceivably alter calling conventions.
 
But as said, I am far from sure on this - hopefully someone more
knowledgeable will make things clear.
"A. Bolmarcich" <aggedor@earl-grey.cloud9.net>: Aug 25 01:51PM -0500

> reason anyone would ever want to use copy initialization
> when writing new code? Are there use cases where copy
> initialization is much better than direct initialization?
 
In "A Tour of C++", Bjarne Stroustrup gave the following advice: "Prefer
the = syntax for the initialization in declarations using auto."
ram@zedat.fu-berlin.de (Stefan Ram): Aug 25 01:50PM

>function but standard is backward there. IOW we have to use 'noexcept'
>massively if we want to get really rid of that one percent as well.
 
I have little experience with this.
 
When can I use the »noexcept« specification and not
be lying to the implementation?
 
In my C++ course, at the beginning, I use
 
- arithmetic operators, can they throw?
 
- »::std::cout << ...«, can this throw?
 
- can one use the 5.3.7 »noexcept« operator in the above
cases to find answers to the above questions?
(If so, could this be done by C++ automatically,
marking a function as »noexcept« when the »noexcept«
operator yields »true« for every expression in the
function?)
 
- library functions, they should be marked appropriately?
 
. Another approach would be to mark /every/ function
»noexcept« in some programs, /even if/ it can throw.
If I read 15.4p10 correctly, the worst thing that can
happen is that »::std::unexpected()« or »::std::terminate()«
is called, and for certain programs this might be ok.
But if the exception in this case still /is/ "handled"
in this sense, will it really be faster with the
»noexcept« specification?
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: