From: Niels Dekker - no reply address on
When the copy-constructor of an object throws an exception while the object
itself is being thrown, I'd expect std::terminate to be called. But it
doesn't seem to happen! At least, not when I use Visual C++. I've tried
both VC 2008 and VC 2010 Beta 1. Is that a known compiler bug? I can't find
it at https://connect.microsoft.com/VisualStudio

Typical example: suppose I have an exception class, MyException, containing
an std::string. This is bad practice, of course, because std::string may
itself throw an exception, while it is being copied. Instead of waiting for
std::string to throw, I simply added "throw std::bad_alloc()" to the
copy-constructor of MyException, for the sake of the test. Please have a
look:

//////////////////////////////////////////////////
#include <cstdlib>
#include <stdexcept>
#include <string>

class MyException: public std::logic_error
{
std::string m_string;
public:
MyException(const std::string& arg)
:
std::logic_error(arg), m_string(arg) {}

// A throwing copy-constructor!
MyException(const MyException& arg)
:
std::logic_error(arg), m_string(arg.m_string)
{
// Triggering std::terminate...?
throw std::bad_alloc();
}

~MyException() throw() { }
};

int main()
{
const MyException constException("what");
try
{
// Here the copy-constructor is called:
throw constException;
}
catch( std::bad_alloc & )
{
// Here is where we get!
return EXIT_FAILURE;
}
}
//////////////////////////////////////////////////

Shouldn't the above test program call std::terminate, instead of catching
the std::bad_alloc?


Kind regards,

Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center


From: Martin B. on
Niels Dekker - no reply address wrote:
> When the copy-constructor of an object throws an exception while the object
> itself is being thrown, I'd expect std::terminate to be called. But it
> doesn't seem to happen! At least, not when I use Visual C++. I've tried
> both VC 2008 and VC 2010 Beta 1. Is that a known compiler bug? I can't find
> it at https://connect.microsoft.com/VisualStudio
>
> Typical example: suppose I have an exception class, MyException, containing
> an std::string. This is bad practice, of course, because std::string may
> itself throw an exception, while it is being copied. Instead of waiting for
> std::string to throw, I simply added "throw std::bad_alloc()" to the
> copy-constructor of MyException, for the sake of the test. Please have a
> look:
>
> //////////////////////////////////////////////////
> #include <cstdlib>
> #include <stdexcept>
> #include <string>
>
> class MyException: public std::logic_error
> {
> std::string m_string;
> public:
> MyException(const std::string& arg)
> :
> std::logic_error(arg), m_string(arg) {}
>
> // A throwing copy-constructor!
> MyException(const MyException& arg)
> :
> std::logic_error(arg), m_string(arg.m_string)
> {
> // Triggering std::terminate...?
> throw std::bad_alloc();
> }
>
> ~MyException() throw() { }
> };
>
> int main()
> {
> const MyException constException("what");
> try
> {
> // Here the copy-constructor is called:
> throw constException;
> }
> catch( std::bad_alloc & )
> {
> // Here is where we get!
> return EXIT_FAILURE;
> }
> }
> //////////////////////////////////////////////////
>
> Shouldn't the above test program call std::terminate, instead of catching
> the std::bad_alloc?
>
>

AFAIK, the implementation is *allowed* to copy the exception object but
is not required to, so it may just be that at runtime the copy-ctor is
never called.

br,
Martin
From: Niels Dekker - no reply address on
>> class MyException: public std::logic_error
>> {
>> std::string m_string;
>> public:
>> MyException(const std::string& arg)
>> :
>> std::logic_error(arg), m_string(arg) {}
>>
>> // A throwing copy-constructor!
>> MyException(const MyException& arg)
>> :
>> std::logic_error(arg), m_string(arg.m_string)
>> {
>> // Triggering std::terminate...?
>> throw std::bad_alloc();
>> }
>>
>> ~MyException() throw() { }
>> };
>>
>> int main()
>> {
>> const MyException constException("what");
>> try
>> {
>> // Here the copy-constructor is called:
>> throw constException;
>> }
>> catch( std::bad_alloc & )
>> {
>> // Here is where we get!
>> return EXIT_FAILURE;
>> }
>> }
>>
>> Shouldn't the above test program call std::terminate, instead of
>> catching the std::bad_alloc?

Martin replied:
> AFAIK, the implementation is *allowed* to copy the exception object
> but is not required to, so it may just be that at runtime the
> copy-ctor is never called.

Thanks, Martin. In some cases, the compiler is indeed allowed to omit the
copy-constructor call. But in this case, I don't think it is allowed. The
test program certainly *does* call the copy-constructor of MyException, when
compiled by VC. So don't you think it should trigger a call to
std::terminate?

Doesn't note 141 from the C++ Working Draft apply here? As follows:

"For example, if the object being thrown is of a class with a copy
constructor, std::terminate() will be called if that copy constructor exits
with an exception during a throw."

See also: Working Draft, Standard for Programming Language C++, section
15.5.1, The std::terminate() function, [except.terminate],
www.open-std.org/JTC1/sc22/WG21/docs/papers/2009/n3000.pdf

Kind regards,

Niels


From: Martin B. on
Niels Dekker - no reply address wrote:
>>> class MyException: public std::logic_error
>>> {
>>> std::string m_string;
>>> public:
>>> MyException(const std::string& arg)
>>> :
>>> std::logic_error(arg), m_string(arg) {}
>>>
>>> // A throwing copy-constructor!
>>> MyException(const MyException& arg)
>>> :
>>> std::logic_error(arg), m_string(arg.m_string)
>>> {
>>> // Triggering std::terminate...?
>>> throw std::bad_alloc();
>>> }
>>>
>>> ~MyException() throw() { }
>>> };
>>>
>>> int main()
>>> {
>>> const MyException constException("what");
>>> try
>>> {
>>> // Here the copy-constructor is called:
>>> throw constException;
>>> }
>>> catch( std::bad_alloc & )
>>> {
>>> // Here is where we get!
>>> return EXIT_FAILURE;
>>> }
>>> }
>>>
>>> Shouldn't the above test program call std::terminate, instead of
>>> catching the std::bad_alloc?
>
> Martin replied:
>> AFAIK, the implementation is *allowed* to copy the exception object
>> but is not required to, so it may just be that at runtime the
>> copy-ctor is never called.
>
> Thanks, Martin. In some cases, the compiler is indeed allowed to omit the
> copy-constructor call. But in this case, I don't think it is allowed. The
> test program certainly *does* call the copy-constructor of MyException, when
> compiled by VC. So don't you think it should trigger a call to
> std::terminate?
>

How do you verify that the copy-ctor is called?
Have you added some tracing, do you set a breakpoint?
Are you running the process under the debugger? release/debug
compilation? What operating system are you using exactly?

br,
Martin
From: Niels Dekker - no reply address on
Martin B. wrote:
> How do you verify that the copy-ctor is called?
> Have you added some tracing, do you set a breakpoint?

Yes, when I run within Visual Studio 2008, having a breakpoint in the
copy-constructor, it gets there.

> Are you running the process under the debugger?
> release/debug compilation?

I tried both debug and compilation. Neither of them appear to do an
std::terminate. Both compilations produce a similar output:

First-chance exception at 0x... in MyTest.exe: Microsoft C++ exception:
std::bad_alloc at memory location 0x...
The program '[...] MyTest.exe: Native' has exited with code 1 (0x1).

> What operating system are you using exactly?

Windows XP Professional.

Are you able to reproduce it? Maybe a slightly extended main() function
could be helpful, as follows:

//////////////////////////////////////////////////
int main()
{
const MyException constException("what");
try
{
// Here the copy-constructor is called:
throw constException;
}
catch( MyException & referenceToMyException )
{
// Modify the exception. So this must be a copy!
// Note that we don't actually get here.
referenceToMyException = MyException("");
}
catch( std::bad_alloc & )
{
// Here is where we get!
return EXIT_FAILURE;
}
// This line is never reached.
return 0;
}

//////////////////////////////////////////////////

Here I hope you see more clearly that constException *must* be copied, in
order to support the /potential/ assignment to referenceToMyException. (Note
that the original exception object is "const".) Also I added "return 0" at
the end, for clarity. Although it is never reached, because the program
always returns EXIT_FAILURE, when compiled on VC. Please let me know if you
agree that std::terminate should be called instead!

Kind regards,

Niels
--
Niels Dekker
http://www.xs4all.nl/~nd/dekkerware
Scientific programmer at LKEB, Leiden University Medical Center