From: Bo Persson on 3 Dec 2009 13:17 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? > > 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 No, it doesn't really apply because the std::bad_alloc appears before and not during the throw! :-) You throw by value, and I believe the implementation is allowed to create a copy *before* the copy is thrown. This is similar to evaluating all parameters before calling a function. Bo Persson
From: James Kanze on 4 Dec 2009 05:20 On Dec 3, 6:17 pm, "Bo Persson" <b...(a)gmb.dk> wrote: > 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? > > 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 > No, it doesn't really apply because the std::bad_alloc appears > before and not during the throw! :-) > You throw by value, and I believe the implementation is > allowed to create a copy *before* the copy is thrown. This is > similar to evaluating all parameters before calling a > function. I don't see where you get this. There are two parts of a throw expression: the expression which defines what is being thrown, and the throw itself. In this case, the expression which defines what is being thrown is simply constExpression, an lvalue of type MyException. I don't see any place in the standard that allows any copies here. Then we enter into the throw itself, which does copy. But here, 15.5.1 is clear: In the following situations exception handling must be abandoned for less subtle error handling techniques: -- when the exception handling mechanism, after completing evaluation of the expression to be thrown but before the exception is caught (15.1), calls a user function that exits via an uncaught exception, A user defined copy constructor is in fact about the only I can think of which could be called, and it is, in fact, mentionned in a footnote---non normative, but a very clear indication of intent. -- James Kanze
From: Niels Dekker - no reply address on 4 Dec 2009 14:29 >> Doesn't note 141 from the C++ Working Draft [N3000] 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." Bo Persson wrote: > No, it doesn't really apply because the std::bad_alloc appears > before and not during the throw! :-) > > You throw by value, and I believe the implementation is > allowed to create a copy *before* the copy is thrown. This is > similar to evaluating all parameters before calling a > function. James Kanze wrote: > I don't see where you get this. There are two parts of a throw > expression: the expression which defines what is being thrown, > and the throw itself. In this case, the expression which > defines what is being thrown is simply constExpression, an > lvalue of type MyException. I don't see any place in the > standard that allows any copies here. Then we enter into the > throw itself, which does copy. But here, 15.5.1 is clear: > > In the following situations exception handling must be > abandoned for less subtle error handling techniques: > > -- when the exception handling mechanism, after completing > evaluation of the expression to be thrown but before the > exception is caught (15.1), calls a user function that > exits via an uncaught exception, > > A user defined copy constructor is in fact about the only I can > think of which could be called, and it is, in fact, mentionned > in a footnote---non normative, but a very clear indication of > intent. Thanks! I think I'll submit a bug report to connect.microsoft.com this weekend. Unless I can still get convinced that it's not a compiler bug, of course... Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center
From: Martin B. on 7 Dec 2009 07:05 Niels Dekker - no reply address wrote: > 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? > ......... > 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! > I've tried this with VS2005 (VC8) and I can confirm the behaviour, however I would like to add the following: a) throw MyException("anonymous") + catch-by-ref = This will *not* invoke the copy-ctor and so will correctly catch MyException by reference b) throw MyException("anonymous") + catch-by-value = This needs a copy-ctor call at the catch site, and it *will* correctly call std::terminate c) const MyException cExcObj("named const") + throw cExcObj + catch-by-* = This requires a copy-ctor call, but the copy-ctor call is done *before* the throw and thus it will just raise the bad_alloc. From what James wrote, I guess this is non std compliant. br, Martin
From: Niels Dekker - no reply address on 7 Dec 2009 07:41 Martin B. wrote: > I've tried this with VS2005 (VC8) and I can confirm the behaviour, > however I would like to add the following: > > a) throw MyException("anonymous") + catch-by-ref = This will *not* > invoke the copy-ctor and so will correctly catch MyException by > reference > b) throw MyException("anonymous") + catch-by-value = This needs a > copy-ctor call at the catch site, and it *will* correctly call > std::terminate > > c) const MyException cExcObj("named const") + throw cExcObj + > catch-by-* = This requires a copy-ctor call, but the copy-ctor call > is done *before* the throw and thus it will just raise the bad_alloc. > From what James wrote, I guess this is non std compliant. Thanks Martin. That's also according to my observation. However, the notes from April, 2006 at www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#475 appear to support Bo's point of view: > > The CWG agreed with the position that std::uncaught_exception() should > return false during the copy to the exception object and that > std::terminate() should not be called if that constructor exits with an > exception. The issue was returned to "drafting" status for rewording to > reflect this position. (Thanks to Daniel Kruegler for the link!) I'm still considering to submit a bug report to Microsoft, mainly to have this behavior documented... Kind regards, Niels -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: Changing file attributes, Windows Explorer way. Next: mempcpy and uname |