Throwing exception that has const reference to local variable - c++

What happens to the local variables during stack unwinding, that are referenced in exception? Consider following code:
class bar;
class my_error
{
public:
my_error(const bar& bar) : _bar(bar) {}
const bar& get_bar() const { return _bar; }
private:
const bar& _bar;
}
...
bar some_local_object(...);
if (!foo()) {
throw my_error(some_local_object);
}
...
try {
g();
} catch (my_error& e) {
e.get_bar()
...
}
What happens to some_local_object? Shouldn't it be destroyed during stack unwinding? Is it safe to use it, as provided in example?
Additional question
As already answered, this code would lead to undefined behavior. My second question to it is:
If I am neither allowed to pass reference to local object nor should I try to make copy of it, because in rare case it could cause bad_alloc (which is why, I guess, gcc standard library has no meaningful error message, i.e. map.at throws exception for which what() returns "map.at"), then what is a good strategy to pass additional information? Note that even joining multiple strings, during construction of error message could theoretically cause bad_alloc. i.e.:
void do_something(const key& k, ....)
{
...
if (!foo(k)) {
std::ostringstream os;
os << "Key " << k << " not found"; // could throw bad_alloc
throw std::runtime_error(os.str());
}
// another approcach
if (!foo(k)) {
throw key_not_found(k); // also bad, because exception could outlive k
}
}

The behavior is the same as when returning a reference to a variable on the stack: the object is destroyed before you get to use it. That is, by the time the exception is caught, the referenced object is destroyed and all access to the reference result in undefined behavior.
The relevant clause in the standard is 15.2 [except.ctor] paragraph 1:
As control passes from the point where an exception is thrown to a handler, destructors are invoked for all automatic objects constructed since the try block was entered. The automatic objects are destroyed in the reverse order of the completion of their construction.

The local object is destroyed during stack unwinding. The reference then becomes invalid, a dangling reference. Which means that inspection of the exception object such that the reference is used, will have Undefined Behavior.

Related

Is throwing a temporary value as reference undefined behavior?

To my surprise, std::runtime_error only has a const std::string& constructor, but no value constructor. Thus I am wondering if throw std::runtime_error("Temporary" + std::to_string(100)); is defined. After all we are creating an exception object that refers to a temporary object inside the scope of a function that immediately exits (as we throw out of it). Further investigation showed that while returning a constant reference to a temporary value immediately causes a segfault on my system, throwing one doesn't:
const std::string& undefined_behavior() {
return "Undefined " + std::to_string(1);
}
void test() {
throw std::runtime_error("Hello : " + std::to_string(2));
}
void test2() {
const std::string& ref = "Hello : " + std::to_string(3);
throw ref;
}
int main(int argc, char** argv) {
//std::cout << undefined_behavior() << std::endl;
try {
test();
} catch(const std::runtime_error& ex) {
std::cout << ex.what() << std::endl;
}
try {
test2();
} catch(const std::string& ref) {
std::cout << ref << std::endl;
}
}
On my system, undefined_behavior() crashes immediately but test() and test2() run fine.
While I know the call to undefined_behavior() is undefined behavior, is test() and test2() undefined? If not, do thrown values get a specfied treatment?
And if they are all undefined but happened to work on my computer by accident, what is the proper way to throw an exception with a variable message?
The const std::string& constructor doesn't cause the exception object to store a reference to the passed std::string. std::runtime_error will make an internal copy of the passed string (although the copy will be stored in an usual way, probably reference-counted in an allocation external to the exception object; this is to give better exception guarantees when the exception object is copied, which the standard requires).
A function taking a const lvalue reference doesn't usually mean that it takes ownership or stores a reference to the object.
Prior to C++11 there was no reason to not use a const reference here, since it was always more efficient than passing by-value. With C++11 move semantics that changed and it is true that usually these kind of constructors had rvalue reference variants added with C++11, so that passing a temporary std::string object to the constructor would allow more efficient move-construction instead of copy-construction.
My guess is that this simply never was done for the exception classes because the performance of their construction should not be important in comparison to the overhead of actually throwing the exception.
So in test()'s case a temporary string object is created from the + operation, which is passed to the constructor and the exception object will make a copy of it. After the initialization of the exception object the temporary string is destroyed, but that is not a problem, since the exception object stores/references a copy.
In test2() the same would apply if you had written throw std::runtime_error(ref). However, here a reference is bound immediately to the temporary object materialized from the return value of +. This causes its lifetime to be extended to that of the reference variable. Therefore again, the temporary lives long enough for the std::runtime_error to make a copy from it.
But since you write simply throw ref that is not exactly what happens. throw ref will throw a std::string, because that is the type of the ref expression. However, throw doesn't actually use the object referenced by the expression as exception object. The exception object is initialized from the operand of the throw expression. So here, the exception object will be another std::string object (in unspecified storage) which will be initialized from the temporary that ref refers to.
undefined_behavior() has undefined behavior when the return value is used, because the temporary std::string object materialized from the + return value and which the return value of undefined_behavior() references is not lifetime-extended. Although it is again immediately bound by a reference, the lifetime-extension rule specifically doesn't apply to objects bound to a reference in a return value initialization. Instead the temporary is destroyed when the function returns, causing the function to always return a dangling reference.
It is not undefined behavior.
In test1(), the constructor of std::runtime_error makes an internal copy. There is even a note on this at cppreference:
Because copying std::runtime_error is not permitted to throw
exceptions, this message is typically stored internally as a
separately-allocated reference-counted string. This is also why
there is no constructor taking std::string&&: it would have to
copy the content anyway.
In test2() there is no std::runtime_error involved. Instead, as you can read e.g. here, in the following statement
throw expr;
the exception object is copy-initialized from expr. So there is a copy made of that temporary string also in this case.

Destructor not invoked when an exception is thrown in the constructor

Why is the destructor not invoked in this code?
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; throw; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
EDIT
From the answers, In understand that when an exception happens in the constructor, destructor will not be invoked. But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked? If not, then why it is a smart pointer?
Adding the code
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
int main()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
std::cout << myinst->increment() << '\n';
std::cout << myinst->increment() << '\n';
}
Output:
MyClass Allocated
terminate called after throwing an instance of 'int'
Aborted
A C++ object's lifetime begins only after its constructor completes successfully.
Since the exception was thrown before constructor call was complete you don't have an complete object and hence no destructor.
Herb Sutter explains this nicely, to quote him:
Q: What does emitting an exception from a constructor mean?
A: It means that construction has failed, the object never existed, its lifetime never began. Indeed, the only way to report the failure of construction -- that is, the inability to correctly build a functioning object of the given type -- is to throw an exception. (Yes, there is a now-obsolete programming convention that said, "if you get into trouble just set a status flag to 'bad' and let the caller check it via an IsOK() function." I'll comment on that presently.)
In biological terms,
conception took place -- the constructor began -- but despite best efforts it was followed by a miscarriage -- the constructor never ran to term(ination).
Incidentally, this is why a destructor will never be called if the constructor didn't succeed -- there's nothing to destroy. "It cannot die, for it never lived." Note that this makes the phrase "an object whose constructor threw an exception" really an oxymoron. Such a thing is even less than an ex-object... it never lived, never was, never breathed its first. It is a non-object.
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed as an object.
EDIT 1:
But if the exception happens in the main(), ie after the MyClass object is fully instantiated, will the MyClass destructor be invoked?
Yes, it will be!
That is the purpose of using scoped_ptr, Once an exception is thrown in main, Stack Unwinding would cause all local objects to be deallocated, this means that myinst(which resides on stack) will also be deallocated, which in turn will call the destructor of MyClass.
Refer the Boost doccumentation when in doubt:
The scoped_ptr class template stores a pointer to a dynamically allocated object. (Dynamically allocated objects are allocated with the C++ new expression.) The object pointed to is guaranteed to be deleted, either on destruction of the scoped_ptr, or via an explicit reset
EDIT 2:
Why does your edited program crash?
Your program shows crashes because, You throw an exception but you never catch it. when such a scenario occurs an special function called terminate() is called whose default behavior is to call abort().It is implementation defined behavior whether stack is Unwound before terminate() is called in this particular scenarioRef 1.Seems your implementation doesn't & you should not rely on this behavior as well.
You can modify your program as follows to handle the exception and you should get the behavior you were expecting:
#include <boost/scoped_ptr.hpp>
#include <iostream>
class MyClass {
boost::scoped_ptr<int> ptr;
public:
MyClass() : ptr(new int) { *ptr = 0; std::cout<<"MyClass Allocated\n"; }
~MyClass() { std::cout<<"MyClass De-allocated\n"; }
int increment() { return ++*ptr; }
};
void doSomething()
{
boost::scoped_ptr<MyClass> myinst(new MyClass);
throw 3;
}
int main()
{
try
{
doSomething();
}
catch(int &obj)
{
std::cout<<"Exception Handled";
}
}
Ref1C++03 15.5.1 The terminate() function
In the following situations exception handling must be abandoned for less subtle error handling techniques:
....
— when the exception handling mechanism cannot find a handler for a thrown exception (15.3),
....
In such cases,
void terminate();
is called (18.6.3). In the situation where no matching handler is found, it is implementation-defined whether or not the stack is unwound before terminate() is called. In all other situations, the stack shall not be unwound before terminate() is called. An implementation is not permitted to finish stack unwinding prematurely based on a determination that the unwind process will eventually cause a call to terminate().
Because calling the destructor doesn't make sense in this case.
You only destruct things which are constructed, yet your object never fully constructs. Your class members have been constructed, though, and will have their destructors called.
If a constructor throws exception, then the destructor of the class will not be called, because the object is not fully constructed.
See this link how to manage resources in such situation:
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.10
When the exception is thrown from the constructor (beginning or half way or at the end of the call), then it's assured that the object is not constructed.
So it's well defined not to invoke the destructor of an object which was never constructed.
Here is one related FAQ from Bjarne's website.
The destructor for MyClass was never invoked because no objects of type MyClass were ever constructed. Each attempt to construct one was aborted, due to the exception being thrown.
As an aside, if you want your debug messages to display -- especially if you're dealing with the program crashing -- you really ought to flush the streams: i.e. using std::endl instead of '\n' at the end of line. (or inserting std::flush)
While merely using '\n' often works, there are enough situations where it fails and it's really, really confusing to debug if you don't make a habit of doing things right.

What happens when we throw an object/variable to catch?

Two Questions
1) What happens when an Object/variable is thrown to catch? Say for example,
int foo() {
FILE *fp = ....;
int dummy = 10;
int *dummy_ptr = new int[10];
throw 1;
}
int main() {
try {
foo();
} catch (int &i) {
std::cout<<"ERROR, the value is "<<i<<std::endl;
}
}
In this situation, what happens here? A new variable created and then passed???
what if I use a pointer or a variable without reference
like
catch(int *i) // or catch (int i)
Also, does all the variables/resources declared or initiated inside the scope has been freed/closed?
2) Also in the case of rethrow,
if I plan to rethrow with a reference, the second catch gets a new variable, if I i rethrow with without reference (i.e) by value, then the changes done in the intermediate throw is not affected....
int goo() {
throw 2;
}
int foo() {
try{
goo();
} catch(int &i) { // (or) catch(int i) // i is not changing in the next line.
i = 2;
throw;
}
}
int main() {
try {
foo();
} catch (int &i) {
std::cout<<"ERROR, the value is "<<i<<std::endl;
}
}
OUTPUT:
catch(int &i) // prints 2
catch(int i) // prints 1
From my judgment,
What I think is, as long as it is reference, the value gets affected,
if its 'pass by value' in the intermediate step. it still throws the original object to the second catch.
(i.e) the control flow for the variable is really not throw the intermediate catch.....
In this situation, what happens here? A new variable created and then passed?
Yes; when you throw an object it's created somewhere, and then destroyed once the exception has been handled (that is, after leaving the catch block without rethrowing).
what if I use a pointer or a variable without reference? Also in the case of rethrow...
If you catch by value then you'll get a copy of that object - if you rethrow the exception, then the next handler will get a new copy of the original, and won't see any changes you might have made. Catching by reference will give you a reference to the thrown object - if you rethrow, then the next handler will see any changes you made. You can't catch the object by pointer - you'll only catch a pointer if a pointer was thrown.
Also, does all the variables declared or initiated inside the scope has been closed?
When an exception is thrown all automatic variables are destroyed, in the scope of the throw and all enclosing scopes until the handler is reached. Dynamically allocated variables (such as your new int[10]) are not deleted, and arbitrary clean-up functions like fclose are certainly not called for FILE* variables, unless they are managed by a scope-based object such as a smart pointer.
Yes, when an exception is thrown all automatic variables are
destroyed, in the scope of the throw and all enclosing scopes until
the handler is reached.
One note on this,
your memory in dummy_ptr* will not be deallocated, and your FILE pointer fp* will not be closed.
I don't think you can call it a variable; it doesn't have a name. But a
new object of type int is created, in an unspecified place determined
by the implementation. When you catch by reference, the reference is
bound to that hidden object. And when you fall off the end of the catch
block, or leave the catch block by any means other than rethrowing the
same exception, the object is “freed”.

If you catch an exception by reference, can you modify it and rethrow?

Does the standard have anything to say about an exception that is caught by reference and what happens to attempts to modify it?
Consider the following code:
class my_exception: public std::logic_error
{
public:
std::vector<std::string> callstack;
};
void MyFunc()
{
try
{
SomethingThatThrows();
}
catch (my_exception & e)
{
e.callstack.push_back("MyFunc");
throw;
}
}
This is a contrived example, I'm not actually attempting something like this. I was just curious what would happen, based on the suggestion in another thread that exceptions should be caught by const reference.
The exception will change.
§15.3[except.handle]/17:
When the handler declares a non-constant object, any changes to that object will not affect the temporary
object that was initialized by execution of the throw-expression.
When the handler declares a reference to
a non-constant object, any changes to the referenced object are changes to the temporary object initialized
when the throw-expression was executed and will have effect should that object be rethrown.
So if my_exception is caught outside of MyFunc, we'll see the "MyFunc" entry in the callstack (e.g. http://ideone.com/5ytqN)
Yes, you can do this.
When you rethrow the current exception using throw;, no copies are made: the original temporary exception object is rethrown. Thus, any changes you make to that object in the handler will be present in the exception object when you next catch it.

Thrown object copy constructs -- why?

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 &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.