开发者

Thrown object copy constructs -- why?

开发者 https://www.devze.com 2023-02-19 08:27 出处:网络
I want to be able to throw a constructed object, but modify it just before it\'s thrown (using the Named Parameter Idiom).

I want to be able to throw a constructed object, but modify it just before it's thrown (using the Named Parameter Idiom). Given:

#include <iostream>
#include <exception>

using namespace std;

struct my_exception : std::exception { 
  my_exception() { 
    cout << "my_exception(): this=" << hex << (unsigned long)this << endl;
  }

  my_exception( my_exception const& ) { 
    cout << "my_exception( my_exception const& )" << endl;
  }

  ~my_exception() throw() { 
    cout << "~my_exception()" << endl;
  }

  my_exception& tweak() { 
    return *this;
  }

  char const* what() const throw() { return "my_exception"; }
};

int main() {
  try {
    throw my_exception().tweak();
  }
  catch ( my_exception const &am开发者_开发技巧p;e ) { 
    cout << "&e=" << hex << (unsigned long)&e << endl;
  }
}

When I run the program, I get:

my_exception(): this=7fff5fbfeae0
my_exception( my_exception const& )
~my_exception()
&e=1001000f0
~my_exception()

As you can see, the exception object caught is not the one that's originally thrown. If I remove the call to tweak(), I instead get:

my_exception(): this=1001000f0
&e=1001000f0
~my_exception()

For the case where tweak() is called, why is the copy constructor called? I want tweak() to operate on the originally constructed object and no copy to be made. Is there any way to prevent the copy construction?

FYI: I'm using g++ 4.2.1 (part of Xcode on Mac OS X).


An exception is thrown by value. You can't throw a reference as a reference. When you try, the object gets copied (using the statically known type).

By the way, this one reason why it's a good idea to make exceptions cloneable, and to have virtual rethrower method.

EDIT (see comments): For example, it's Undefined Behavior to propagate an exception through a C callback. But if you have defined a suitable exception class then you can clone it, and in C++-land again up the call chain rethrow via virtual method.

Cheers & hth.,


To add to Alf's answer, the fact that you aren't getting a copy operation when you don't call tweak() is because the standard permits (but doesn't require) eliding calls to the copy constructor to create the temporary exception object. From C++03 15.1/5 (Throwing an exception):

If the use of the temporary object can be eliminated without changing the meaning of the program except for the execution of constructors and destructors associated with the use of the temporary object (12.2), then the exception in the handler can be initialized directly with the argument of the throw expression. When the thrown object is a class object, and the copy constructor used to initialize the temporary copy is not accessible, the program is ill-formed (even when the temporary object could otherwise be eliminated).

If you make the copy constructor private, gcc will give you an error (even though when the constructor is public it doesn't get called). MSVC will not give an error, but it should I think.


AFAIK the following happens in your line throw my_exception().tweak(); :

new my_exception object is created (locally, on the stack), tweak() returns reference to this local object. Then, when you throw this reference, you go out of the scope and local object gets deleted. So, the implementation copies the class to dynamic memory to keep reference valid.

In the second case you throw it by value and it is allocated in dynamic memory at once.

0

精彩评论

暂无评论...
验证码 换一张
取 消