Is it safe to use unique_ptr in an Exception class - c++

Is it safe to use unique_ptr?
When I use cout in destructor, sometimes it called more then one time. - so it make copy time-to-time. if it take two copy from one object - data can be lost..
#include <memory>
class MyException
{
std::unique_ptr<Type> data;
MyException();
~MyException() {cout<<"test"<<endl;}
MyException(MyException ex&);
};
int main()
{
try
{
try
{
throw MyException();
}
catch (const MyException& ex)
{
throw;
//or?
throw ex; //will be copied?
}
return 0;
}
catch(const MyException/*& will be missed. will ex be copied?*/ ex)
{
throw; //wich ex will be re-throw, copy or original?
//or?
throw ex; //will be copied?
}
}
Can I be sure, that data will not be lost between re-throws?
And is this good practic to use ptr inside exception to collect error info from different levels?
Also, can MyException.data be lost after:
std::exception_ptr ex = std::current_exception();
std::rethrow_exception(ex);

As you discovered, you should always say throw; when you want to re-throw an exception, not not throw ex;. Indeed, throw ex; will copy (and slice, if ex is a reference to a base class!).
So, always catch by reference, and always re-throw without naming the exception.

With gcc 4.7.3 your example doesn't compile, complaining about a missing copy constructor for MyException. This is in the line where it's first thrown, so throw MyException() itself already wants to make a copy (at least in gcc). See also this stackoverflow question and the C++ FAQ.
To answer your question about whether using pointers in exceptions is good practice, I would generally say no. Unless the data to be piggybacked onto the exception is huge (which would likely be a design problem), a stack allocated data structure should be preferred. Performance shouldn't be the main concern during exception handling anyway, so copying stuff around isn't a real problem.
If you really need a pointer (maybe Type has no copy constructor and you can't change that), using shared_ptr could help you in a pinch, although I feel like that would be an ugly hack. I would probably try and reduce the information passed via the exception to the bare minimum that would help callers identify and handle the problem.
Edit: I found the relevant section in the C++ standard, section 15.1, paragraph 5:
When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided.
So it's actually not legal C++ to throw an exception object without a copy constructor.

Related

Why smart pointer templates need to disable exception throwing in constructor

I find such question while reading the Smart Pointer Template Classes in C++ primer plus.
The book gives an example of how auto_ptr class is implemented, like this,
template<class X> class auto_ptr {
public:
explicit auto_ptr(X* p = 0) throw();
...};
throw() at the end of constructor means this constructor doesn't throw an exception.
I know this is deprecated, but I do not know why it needs to disable its exception throwing.
throw() doesn't disable exception throwing. It simply says that the function does not throw any exceptions. That's a statement about the code in the constructor: there's nothing there that will throw an exception that escapes from the constructor. That means that either the code in the constructor doesn't throw any exceptions (for example, int i = 3; will not throw an exception), or that anything that does throw an exception is enclosed in a try block whose catch clauses don't throw anything.
Because if the constructor of auto_ptr would throw exceptions, the pointer might be lost and then cause memory leak. For example:
auto_ptr<int> ap(new int);
The memory allocated couldn't be deallocated again if the constructor failed.
They are declaring an intent/promise not to throw exceptions - they still can, but will be smacked down hard by the runtime if they do.
The reason to use noexcept over throw() is mostly academic.

C++: Throwing an exception invokes the copy constructor?

We have an custom error class that is used whenever we throw an exception:
class AFX_CLASS_EXPORT CCLAError : public CObject
It has the following copy constructor defined:
CCLAError(const CCLAError& src) { AssignCopy(&src); } // (AssignCopy is a custom function)
It was originally written and compiled / linked with MSVC6 (Visual Studio 2003). I am in the process of doing necessary changes to get it to compile and link against MSVC8+ (VS 2008+)
When the msvc8 linker is invoked, i get the following error:
LNK2001: unresolved external symbol "private: __thiscall CObject::CObject(class CObject const &)" (??0CObject##AAE#ABV0##Z)
I understand what the error is telling me: no copy constructor is defined for some child of CObject, so its going all the way up the inheritance tree until it hits CObject, which as no copy constructor defined.
I first saw the error when compiling the library that defines and first throws a CCLAError, which is why I am proceeding as if that is the cause.
I was able to resolve the error by changing
throw CCLAError( ... )
to
throw new CCLAError( ... )
and
catch(CCLAError& e)
{
throw e;
}
to
catch(CCLAError& e)
{
throw;
}
However, I do not understand why re-throwing a caught exception would invoke the copy constructor. Am I missing somethnig completely obvious? Subsequently, why would removing the variable holding a reference to a caught exception cause the copy constructor to not be invoked?
The type of the object thrown must be copyable because the throw expression may make a copy of its argument (the copy may be elided or in C++11 a move may take place instead, but the copy constructor must still be accessible and callable).
Rethrowing the exception using throw; will not create any copies. Throwing the caught exception object using throw e; will cause a copy of e to be made. This is not the same as rethrowing the exception.
Your "updated" code does not work as you expect. catch (CCLAError&) will not catch an exception of type CCLAError*, which is the type of the exception thrown by throw new CCLAError(...);. You would need to catch CCLAError*. Do not do this, though. Throw exceptions by value and catch by reference. All exception types should be copyable.
However, I do not understand why re-throwing a caught exception would invoke the copy constructor.
It doesn't, but re-throwing the thrown exception is done with throw;. When you do throw e; you are requesting to throw a copy of the caught exception.
Several points:
1st of all don't call throw new foo() use throw foo
2nd when your write:
catch(foo const &e) {
throw e;
}
You actually create a new exception, and if for example the exception that
was thrown is subclass of foo they my calling throw e you would loose this
information and actually use a copy constructor to generate foo from e - whatever
it was.
Now when you call
catch(foo const &e) {
throw;
}
You don't create a new exception but rather propagate the same exception.
So: never use throw e; to propagate the exception forward, use throw;
When you throw an exception, the object you're throwing generally resides on the stack. The stack is getting cleaned up as part of the process of throwing, so the compiler must make a copy that can continue to live beyond that point.
When you throw an object with new, you're not throwing the actual object but you're throwing a pointer to the object. That means your catch block must also catch a pointer rather than a reference. Don't forget to delete the pointer or you'll have a memory leak!
When the catch block uses throw; instead of throw e; it can reuse the copy it made earlier and there's no need to make another copy.
It appears that you have misunderstood what re-throw means. When you do -
catch(CCLAError& e)
{
throw e;
}
-- you are NOT rethrowing. Instead, as you have observed, you are indeed creating a copy of the new exception. Instead (again, as you have found for yourself), this is what is technically the correct way to re-throw:
catch(CCLAError& e)
{
throw;
}
Read chapter 14 in Stroustrup's TC++PL (14.3.1 deals with rethrowing).
Also, you do NOT have to do -
throw new CCLAError( ... )
Instead, do -
throw CCLAError( ... )
-- like you were doing before, only receive by CONST reference (you cannot hold a reference to a temporary).
catch(const CCLAError &e)
The language specification allows the compilers to make as many copies of the original object as they want. There is no restriction on the number of copies.
That means, your custom exception class must have an accessible copy-constructor, either the compiler generated one, or user-defined one.

std exceptions inviting unsafe usage?

It is recommended that you always throw something derived from std::exception and there are a few predefines specialisations such as std::runtime_error
std::exception's interface is given in terms of non-throwing accessors. Great. Now look at the constructor for std::runtime_error
class runtime_error : public exception {
public:
explicit runtime_error (const string &);
};
So if I do this
try {
foo ();
}
catch (...) {
throw std :: runtime_error ("bang");
}
it's entirely possible that foo threw because it's out of memory, in which case constructing the string argument to runtime_error can also throw. This would be a throw-expression which itself also throws: won't this will call std::terminate?
Doesn't this mean we should always do this instead:
namespace {
const std :: string BANG ("bang");
}
...
try {
foo ();
}
catch (...) {
throw std :: runtime_error (BANG);
}
BUT WAIT this won't work either, will it? Because runtime_error is going to copy its argument, which may also throw...
...so doesn't this mean that there is no safe way to use the standard specialisations of std::exception, and that you should always roll your own string class whose constructor only fails without throwing?
Or is there some trick I'm missing?
I think your main problem is that you are doing catch(...) and translating to a std::runtime_error thereby losing all type information from the original exception. You should just rethrow with throw().
Practically, if you are short of memory you are likely have a bad_alloc exception thrown at some point and there's not a lot else you can - or should - do. If you want to throw an exception for a reason other than an allocation failed then you are not likely to have a problem constructing a sensible exception object with meaningful contextual information. If you hit a memory issue while formatting your exception object there's not a lot you can do other than propagate the memory error.
You are right that there is a potential problem if you construct a new string object to construct an exception, but if you want to format a message with context this can't be avoided in general. Note that the standard exception objects all have a const char* constructor (as of last week) so if you have a const char* that you want to use you don't have to construct a new std::string object.
std::runtime_error must copy it's argument, but not necessarily as a new string object. There could be an area of statically allocated memory which it can the contents of its argument to. It only has to fulfil the what() requirements which only requires returning a const char *, it doesn't have to store a std::string object.
This would be a throw-expression which itself also throws: won't this
will call std::terminate?
No, it wouldn't. It would just throw the exception about insufficient memory. The control will not reach the outer throw part.
BUT WAIT this won't work either, will it? Because runtime_error is
going to copy its argument, which may also throw...
Exception classes with a throwing copy-constructors are as evil as throwing destructors. Nothing that can really be done about it.
std::runtime_error is designed to treat the usual runtime errors, not
out of memory or other such critical exceptions. The base class
std::exception does not do anything which may throw; nor does
std::bad_alloc. And obviously, remapping std::bad_alloc into an
exception which requires dynamic allocation to work is a bad idea.
The first thing is what would you want to do if you happen to have a bad_alloc exception because you're out of memory?
I'd say in a classic C++ program, you'd want to have the program somehow trying to tell you what happened and then terminates.
In a classic C++ program you'd then let the bad_alloc exception propagate to the main section of the program. The main will contain an arragement of try/catch like this:
int main()
{
try
{
// your program starts
}
catch( const std::exception & e )
{
std::cerr << "huho something happened" << e.what() << std::endl;
}
catch( ... )
{
std::cerr << "huho..err..what?" << std::endl;
}
}
you'll only use catch( ... ) inside the main and at the starting functions of threads. Contrary to some other languages like Java you're not expected to catch all possible exceptions locally. You just let them propagate until you catch them where you wanted to.
Now if you have code that specifically must check std::bad_alloc, you should only catch( const std::bad_alloc & ) locally. And there it should maybe wise to do something else rather than just rethrow another exception.
I found in The C++ Programming Language ยง14.10 also that the C++ exception-handling mechanism keeps a bit of memory to itself for holding exceptions, so that throwing a standard library exception will not throw an exception by itself. Of course it is possible also to let the exception-handling mechanism run out of memory if you really code something perverted.
So, to sum up, if you do nothing and let big exceptions like bad_alloc propagate nicely where you want to catch them, in my opinion you're safe. And you should not use catch( ... ) or catch(const std::exception & ) anywhere except in the main function and in the starting functions of threads.
Catching all exceptions to rethrow a single exception is really the last thing to do. You lose every advantages you got with the C++ exception-handling mechanism.

Throwing, catching, scoping stl::string.c_str() exceptions

Say I've written some function myFunc that can throw const char* exceptions:
void myFunc()
{
int returnCode = whatever();
if (!returnCode)
{
std::string msg;
msg.append("whatever function failed");
std::cerr << msg << std::endl; // print warning message
throw msg.c_str(); // throw warning message as exception
}
}
And later I'm using it like so:
void myProgram()
{
try
{
myFunc();
}
catch(const char* str)
{
// is 'str' string memory valid here?
}
}
I realize this isn't really a good strategy for exception usage: better to throw and catch exception classes, not strings. But I'm curious about the scoping involved here.
msg.str() returns a temporary std::string. As temporaries are deleted at the end of a statement ;, the contents of the character string returned by c_str() become undefined when the throw ... ; statement terminates by leaving the scope via the exception mechanism.
(The lifetime of the const char* temporary is obviously extended to reach to the catch handler, but that does not help since the underlying buffer is gone).
Throwing std::string (i.e. throw msg.str();) would work, the lifetime of the temporary would be extended as intended.
Indeed the c_str() call is acting on a temporary (string) object and the pointer will be invalid when you catch it.
Not only that, but since the stringstream and stringcould do allocation, you need to make sure that you're not throwing because of heap problems. If you're at that point due to being out of memory you may bomb out even worse trying to create your exception. You generally want to avoid heap allocation during exceptional cases.
Are you unable to use say runtime_error or create your own exception type?
Note that if you had said:
throw "error";
you would be OK because the lifetime of the string literal is the lifetime of the program. But don't do it, anyway!
Something Alexander Gessler did not mention in his answer, is the possibility of an exception being thrown by by std::string itself during the creation of the temporary string object.
std::exception is guaranteed not to throw an exception during construction, std::string has no such guarantee.
An alternative approach (for classes) is to declare a private std::string object in your class. Assemble the error message prior to the throw, and then throw the c_str(). This will throw a const char* exception, the error message being valid until the next exception is thrown from that class (which would presumably modify the error string again.)
A simple example can be found here: http://ideone.com/d9HhX
Although this was answered over ten years ago, I would give some supplement:
https://learn.microsoft.com/en-us/cpp/cpp/exceptions-and-stack-unwinding-in-cpp
In the C++ exception mechanism, control moves from the throw statement to the first catch statement that can handle the thrown type. When the catch statement is reached, all of the automatic variables that are in scope between the throw and catch statements are destroyed in a process that is known as stack unwinding.
That's to say, any variables in the stack, including object variable, or basic type(int, char, etc) will be destroyed.
When throw an object in c++, c++ will actually make a cloned object by invoking the object copy constructor, the cloned object lifetime will valid through throw-catch.
reference:
C++: Throwing an exception invokes the copy constructor?
Now, return to the OP question, so, "throw msg.c_str();" is invalid because the msg object
is deleted (it's a auto variable), it happens to work because the memory is still there but actually freed.
So, just as #AlexanderGessler, #MarkB suggested,
the best c++ practice is: always throw string object, runtime_error, instead of throwing string.c_str()

catching exception objects by reference, temporaries, lifetime issues

Consider the following code:
#include <iostream>
#include <stdexcept>
void foo()
{
throw std::runtime_error("How long do I live?");
}
int main()
{
try
{
foo();
}
catch (std::runtime_error& e)
{
std::cout << e.what() << std::endl;
}
}
Why can I catch the exception by reference, isn't std::runtime_error("How long do I live?") an rvalue?
How come the exception object is still alive in the catch block?
Where exactly are thrown exception objects stored? What is their lifetime?
In the C++ standard, paragraph 15.1.4:
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. In particular, if a
handler exits by executing a throw;
statement, that passes control to
another handler for the same
exception, so the temporary remains.
When the last handler being executed
for the exception exits by any means
other than throw; the temporary object
is destroyed and the implementation
may deallocate the memory for the
temporary object; any such
deallocation is done in an unspecified
way. The destruction occurs
immediately after the destruction of
the object declared in the
exception-declaration in the handler.
Note that, in C++-standard talk, a handler denote a catch block with the correct argument type.
A thrown exception is not a temporary - the compiler-generated exception code keeps a permanent copy of it. So you can bind it to a non-const reference.
[edit]
I just check the standard and it actually refers to a temporary copy. However, the lifetime of the temporary is guaranteed to be at least as long as that of the exception handler.
As Neil said, there is internal compiler magic going on. Also, be aware that the compiler is allowed to create any number of copies of the exception object.
Kudos for trying to understand the details of the language. At the same time, IMHO, it is far more important to understand why you should catch an exception by reference (and throw it by value), than why you can.
People typically use a hierarchy of exception classes, and catching by reference allows you to leverage polymorphism, and catch an exception of the base class, when there is no need to handle individual exception types separately. If you couldn't catch by reference, you would have had to write a catch clause for every possible type of exception that can be thrown in the try clause.