Lifetime of a thrown object caught by reference - c++

The C++ Standard, paragraph 15.1.4 sais:
The memory for the temporary copy of the exception being thrown is allocated in an unspecified way, except as noted in 3.7.3.1. The temporary persists as long as there is a handler being executed for that exception.
I'm wondering why this code crashes (I know that it's not best practice):
class magicException
{
private:
char* m_message;
public:
magicException(const char* message)
{
m_message = new char[strlen(message) + 1];
strcpy(m_message, message);
}
~magicException()
{
cout << "Destructor called." << endl;
delete[] m_message;
}
char* getMessage()
{
return m_message;
}
};
void someFunction()
{
throw magicException("Bang!");
}
int main(int argc, char * argv[])
{
try
{
someFunction();
}
catch (magicException& ex)
{
cout << ex.getMessage() << endl;
}
return 0;
}
Specifically, the destructor of the thrown magicException object gets called before the catch block. If I however add a copy constructor to my class:
magicException(const magicException& other)
{
cout << "Copy constructor called." << endl;
m_message = new char[strlen(other.m_message) + 1];
strcpy(m_message, other.m_message);
}
Then the code works, the destructor gets called at the expected place (the end of the catch block), but interestingly the copy constructor still doesn't get called. Is it optimized away by the compiler (Visual C++ 2008 with optimizations turned off), or am I missing something?

Specifically, the destructor of the
thrown magicException object gets
called before the catch block.
Yes, as your quote from the standard says, a copy is taken by the compiler, and the original (probably) discarded. Your problem is the lack of a copy constructor in your original code. However, a C++ compiler is allowed to remove (or add) copy constructor calls in all sorts of situations, including this one.

Related

Why does an exception thrown in a constructor fully enclosed in try-catch seem to be rethrown?

Considering this silly looking try-catch chain:
try {
try {
try {
try {
throw "Huh";
} catch(...) {
std::cout << "what1\n";
}
} catch(...) {
std::cout << "what2\n";
}
} catch(...) {
std::cout << "what3\n";
}
} catch(...) {
std::cout << "what4\n";
}
its output will surely be (and is) what1, because it will be caught by the closest matching catch. So far so good.
However, when I try to create a constructor for a class that tries to initialise a member via member initialiser list (which will result in an exception being raised) like so:
int might_throw(int arg) {
if (arg < 0) throw std::logic_error("que");
return arg;
}
struct foo {
int member_;
explicit foo(int arg) try : member_(might_throw(arg)) {
} catch (const std::exception& ex) { std::cout << "caught1\n"; }
};
int main() {
try {
auto f = foo(-5);
} catch (...) { std::cout << "caught2\n"; }
}
The output of the program is now:
caught1
caught2
Why is the exception being rethrown here (I assume that it is, otherwise why would two catches fire?)? Is this mandated by the standard or is it a compiler bug? I am using GCC 10.2.0 (Rev9, Built by MSYS2 project).
cppreference has this to say about a function-try-block (which is what we have here):
Every catch-clause in the function-try-block for a constructor must terminate by throwing an exception. If the control reaches the end of such handler, the current exception is automatically rethrown as if by throw.
So there we have it. Your exception is automatically rethrown when the catch on the constructor's member initialization list exits. I guess the logic is that your constructor is deemed to have failed so (after the exception handler in the constructor performs any cleanup, perhaps) the exception is automatically propagated to the caller.
While the other answer gives a great official explanation, there is also a really intuitive way to see why things have to behave this way: Consider the alternative.
I've replaced the int with a string to make the issue obvious, but the same principle applies with arithmetic types as well.
std::string might_throw(const std::string& arg) {
if (arg.length() < 10) throw std::logic_error("que");
return arg;
}
struct foo {
std::string member_;
explicit foo(const std::string& arg) try : member_(might_throw(arg)) {
} catch (const std::exception& ex) { std::cout << "caught1\n"; }
};
int main() {
try {
auto f = foo("HI");
std::cout << f.member_ << "\n"; // <--- HERE
} catch (...) { std::cout << "caught2\n"; }
}
What would be supposed to happen if the exception did not propagate?
Not only did arg never make it to member, but the string's constructor never got invoked at all. It's not even default constructed. Its internal state is completely undefined. So the program would be simply broken.
It's important that the exception propagates in such a way to avoid messes like this.
To pre-empt the question: Remember that the reason initializer lists are a thing in the first place is so that member variables can be initialized directly without having their default constructor invoked beforehand.

How to use std::optional for error handling when creating objects without instantly destructing them?

Error handling is a challenge in C++ constructors. There are several common approaches but all of them has obvious disadvantages. Throwing exceptions for example, may cause leak of the allocated resources earlier in the constructor, making it an error prone approach. Using a static init() method is another common solution, but it goes against the RAII principle.
Studying the subject I found this answer and blog suggesting the use of C++17 feature named std::optional<>, and I found it promising. However it seems that this kind of solution comes with an underlying problem - it triggers the destructor instantly when the user retrieved the object.
Here is a simple code example describing the problem, my code is based on the the above sources
class A
{
public:
A(int myNum);
~A();
static std::optional<A> make(int myNum);
bool isBuf() { return _buf; };
private:
char* _buf;
};
std::optional<A> A::make(int myNum)
{
std::cout << "A::make()\n";
if (myNum < 8)
return {};
return A(myNum);
}
A::A(int myNum)
{
std::cout << "A()\n";
_buf = new char[myNum];
}
A::~A()
{
std::cout << "~A()\n";
delete[]_buf;
}
int main()
{
if (std::optional<A> a = A::make(42))
{
if (a->isBuf())
std::cout << "OK\n";
else
std::cout << "NOT OK\n";
std::cout << "if() finished\n";
}
std::cout << "main finished\n";
}
The output of this program will be:
A::make()
A()
~A()
OK
if() finished
~A()
followed with a runtime error (at least in Visual C++ environment) for attempting to delete a->_buf twice.
I used cout for the reader's convenience as I found this problem debugging a much complex code, but the problem is clear - the return statement in A::make() constructs the objects, but since it is the end of the A::make() scope - the destructor is invoked. The user sure his object is initialized (notice how we got an "OK" message) while in reality it was destroyed, and when we step out of the if() scope in main, a->~A() is invoked once again.
So, am I doing this wrong?
The use of std::optional for error handling in constructors is common, or so I've been told. Thanks in advance
Your class violates the rule of 3/5.
Instrument the copy constructor and simplify main to get this:
#include <optional>
#include <iostream>
class A
{
public:
A(int myNum);
~A();
A(const A& other){
std::cout << "COPY!\n";
}
static std::optional<A> make(int myNum);
bool isBuf() { return _buf; };
private:
char* _buf = nullptr;
};
std::optional<A> A::make(int myNum)
{
std::cout << "A::make()\n";
if (myNum < 8)
return {};
return A(myNum);
}
A::A(int myNum)
{
std::cout << "A()\n";
_buf = new char[myNum];
}
A::~A()
{
std::cout << "~A()\n";
delete[]_buf;
}
int main()
{
std::optional<A> a = A::make(42);
std::cout << "main finished\n";
}
Output is:
A::make()
A()
COPY!
~A()
main finished
~A()
When you call A::make() the local A(myNum) is copied to the retunred optional and its destructor is called afterwards. You'd have the same issue without std::optional (eg by returning an A by value).
The copy constructor I added does not copy anything, but the compiler generated one does make a shallow copy of the char* _buf; member. As you do not properly deep copy the buffer it gets deleted twice which results in the runtime error.
Use a std::vector for the rule of 0, or properly implement the rule of 3/5. Your code invokes undefined behavior.
PS Not directly related to the problem, but you should initialize members instead of assigning to them in the constructors body. Change:
A::A(int myNum)
{
std::cout << "A()\n";
_buf = new char[myNum];
}
to
A::A(int myNum) : _buf( new char[myNum])
{
std::cout << "A()\n";
}
or better yet, use a std::vector as mentioned above.
PPS:
Throwing exceptions for example, may cause leak of the allocated resources earlier in the constructor, making it an error prone approach.
No, throwing from a constructor is common and has no problem when you don't manage memory via raw pointers. Both using a std::vector or a smart pointer would help to make your constructor excpetion safe.

Using RAII to replace the finally block to free memory

I was studying about the RAII mechanism in C++ which replaces the finally of Java.
I wrote the following code to test it:
void foo(int* arr) {
cout << "A" << endl;
throw 20;
cout << "B" << endl;
}
class Finally {
private:
int* p;
public:
Finally(int* arr) {
cout << "constructor" << endl;
p = arr;
}
~Finally() {
cout << "destructor" << endl;
delete(p);
}
};
int main()
{
int * arr = new int[10];
new Finally(arr);
try {
foo(arr);
} catch (int e) {
cout << "Oh No!" << endl;
}
cout << "Done" << endl;
return 0;
}
I want to free the memory which I used for arr so I set a new class Finally which saves the pointer to the array and when it exits the scope it should call the destructor and free it. But the output is:
constructor
A
Oh No!
Done
No call for the destructor. It also does not work when I move the body of main to some other void method (like void foo()). What fix should I do to achieve the desired action?
That's because the object you create with new Finally(arr) doesn't really gets destructed in your program.
Your allocation of the object just throws the object away immediately, leading to a memory leak, but more importantly it's created outside the scope of the try and catch.
For it to work you have to do something like
try {
Finally f(arr);
foo(arr);
} catch (int e) {
cout << "Oh No!" << endl;
}
That would create a new object f in the try, which will then get destructed when the exception is thrown (as well as when it goes out of scope of the try if no exception is thrown).
You're assuming C++ works liked Java. It doesn't, so there are actually a few things wrong in your code
The statement
new Finally(arr);
dynamically allocates a Finally, but it is NEVER released in your code. Hence its destructor is never called.
Instead do
Finally some_name(arr);
This will invoke the destructor of Finally - at the end of main() - which will give the output your expect.
However, the second thing wrong is that the destructor of Finally does delete (p) which gives undefined behaviour, since p is the result (in main()) of new int [10]. To give the code well-defined behaviour, change delete (p) to delete [] p.
Third, with the two fixes above, you are not using RAII. RAII means "Resource Acquisition Is Initialisation", which is not actually what your code does. A better form would be to initialise p using a new expression in Finallys constructor and release it with a correct delete expression in the destructor.
class Finally
{
private:
int* p;
public:
Finally() : p(new int [10])
{
cout << "constructor" << endl;
};
~Finally()
{
cout << "destructor" << endl;
delete [] p;
};
int *data() {return p;};
};
AND replace the first two lines of your main() with a single line
Finally some_name;
and the call of foo() with
foo(some_name.data());
More generally, stop assuming that C++ works like Java. Both languages work differently. If you insist on using C++ constructors like you would in Java, you will write terribly buggy C++ code.

std::exception using message from local object

Is the following code safely throwing an exception with custom message?
#include <exception>
#include <sstream>
#include <string>
#include <iostream>
int main() {
try {
std::ostringstream msg;
msg << "give me " << 5;
throw std::exception(msg.str().c_str());
} catch (std::exception& e) {
std::cout << "exception: " << e.what();
}
}
With VC++-2008 this gives:
exception: give me 5
But now I wonder why the message "give me 5" from the local object msg is still available in the catch-block? By the time the message is printed both the stream- and the temporary string-object should have been deleted? Btw: This way of generating a message for an exception seems also to work accross several functions and also if new memory is allocated in the catch-block before printing the exception.
Or is it necessary to define a custom exception class with a std::string member in order to safely keep the message until printing it.
It's perfectly safe. The constructor that takes a C string as a single parameter makes a copy of the string. The constructor that takes a C string and a length parameter allow you to specify no memory be allocated and stores a pointer to the string (the length parameter is ignored).
Note that these two constructors are extensions to the std::exception class and are not standard. Also be aware that the constructor that takes a C string as a single parameter is not marked as explicit.
It's OK.
Per §15.1/3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object,
called the exception object.
and §15.1/4:
The memory for the exception object is allocated in an unspecified
way, except as noted in 3.7.4.1. If a handler exits by rethrowing,
control is passed to another handler for the same exception. The
exception object is destroyed after either the last remaining active
handler for the exception exits by any means other than rethrowing...
so after throw expression:
the expression will be copied (new object will be created by copy constructor) and you shouldn't worry about the local object.
About the msg and const char* which you're worrying... here is Microsoft's implementation:
exception::exception(const char * const & _What)
: _Mywhat(NULL), _Mydofree(false)
{
_Copy_str(_What);
//^^^^^^^^^^^^^^^^^
}
void exception::_Copy_str(const char * _What)
{
if (_What != NULL)
{
const size_t _Buf_size = strlen(_What) + 1;
_Mywhat = static_cast<char *>(malloc(_Buf_size));
if (_Mywhat != NULL)
{
_CRT_SECURE_STRCPY(const_cast<char *>(_Mywhat), _Buf_size, _What);
//^^^^^^^^^^^^^^^^^^
_Mydofree = true;
}
}
}
It copies the _What not just storing the pointer.
No, it's not safe, because std::exception doesn't have a constructor taking a char* in the standard. You are using an MS extension. To make it portable and safe, use std::runtime_error instead, to which you can pass a std::string in the ctor.

Exceptions - c++

I'm trying to understand the behavior of exceptions in c++.
I wrote the following code:
class A{
public:
A(){
};
~A(){
cout<<"hello";
};
};
int exceptionTest(){
throw "blablabla";
};
int main(){
A sd;
int test = exceptionTest();
return 0;
}
I've noticed that in this case the distructor gets called even though no one caught the exception.
If I change the "main" code to:
int main(){
A* sd = new A();
int test = exceptionTest();
return 0;
}
The distructor will not be called.
Can anyone please tell me what is the reason for the different behavior?
Thanks,
Li
The fact that you are throwing an exception is irrelevant here. In your first example, sd is an object that exists on the stack. When execution exits its scope, for whatever reason, it gets destroyed. In the second example, sd is a pointer to an object that was explicitly allocated using new. This object will not be destroyed until that pointer is passed to delete; since you never do so, your program is currently leaking it.
The standard has the following to say on the matter:
-9- If no matching handler is found in a program, the function terminate() is called; whether or not the stack is unwound before this call to terminate() is implementation-defined.
So your compiler performs stack unwinding (invoking destructors of locals), others may not. For example, with G++ or codepad.org, this program will not output "hello".
Dynamically allocated objects are not destroyed until you explicitly destroy them (with delete or such). In particular, if an exception occurs in the meantime, code may never reach the deallocation statement.
Local variable destructors are called automatically, as soon as the variable is out of scope.
Destructors are never called on pointers, so you must call it yourself.
I've noticed that in this case the distructor gets called even though no one caught the exception.
That's exactly what to expect.
This mechanism is a RAII consequence that makes you "sure" that resources will be freed even if there is an exception. For example :
class File
{
public:
File( const std::string filename ) : file_handler(file_open( filename )) { } // whatever the implementation
~File() { file_close(file_handler); }
private:
FileHandler file_handler;
};
void test(){ throw "This is a test"; }
int main()
{
File file("test.txt");
test();
return false;
}
You're assured that the file will be closed even with the throw. So if you use RAII to manage your resources.
That's because when the exception is thrown, until it get catch, it goes back in the call stack and if there is no catch the local objects are destroyed the way they would be if we got out of scope.
This is not really an answer, but I might clarify the behavior, in case of RAII mechanism, that I understood from the other answer and Mike's comments.
#include <iostream>
class Bar
{
public:
Bar() { std::cout << "Bar constructor" << std::endl; }
~Bar() { std::cout << "Bar destructor" << std::endl; }
};
void foo()
{
throw("Exception");
}
int main()
{
// Variation, add { to create a new scope
Bar bar;
foo();
// Variation : }
return 0;
}
Using g++, this code, where the exception is not catched will output the following:
Bar constructor
terminate called after throwing an instance of 'char const*'
Aborted
Meaning that g++ does not unwind the stack (or let go the variable out of scope, if I understand the "variant" correctly), so the destructor is not called.
However, if you catch the exception:
#include <iostream>
class Bar
{
public:
Bar() { std::cout << "Bar constructor" << std::endl; }
~Bar() { std::cout << "Bar destructor" << std::endl; }
};
void foo()
{
throw("Exception");
}
int main()
{
try
{
Bar bar;
foo();
}
catch (...)
{
// Nothing here
}
return 0;
}
then the output will be
Bar constructor
Bar destructor
and you recover the correct behavior.