From: Niels Dekker - no reply address on 2 Dec 2009 14:52 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 3 Dec 2009 09:07 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 3 Dec 2009 09:57 >> 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 3 Dec 2009 11:13 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 3 Dec 2009 12:32 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
|
Next
|
Last
Pages: 1 2 3 Prev: Changing file attributes, Windows Explorer way. Next: mempcpy and uname |