Why smart pointer templates need to disable exception throwing in constructor - c++

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.

Related

Why is std::unique_ptr::reset() always noexcept?

A recent question (and especially my answer to it) made me wonder:
In C++11 (and newer standards), destructors are always implicitly noexcept, unless specified otherwise (i.e. noexcept(false)). In that case, these destructors may legally throw exceptions. (Note that this is still a you should really know what you are doing-kind of situation!)
However, all overloads of
std::unique_ptr<T>::reset() are declared to always be noexcept (see cppreference), even if the destructor if T isn't, resulting in program termination if a destructor throws an exception during reset(). Similar things apply to std::shared_ptr<T>::reset().
Why is reset() always noexcept, and not conditionally noexcept?
It should be possible to declare it noexcept(noexcept(std::declval<T>().~T())) which makes it noexcept exactly if the destructor of T is noexcept. Am I missing something here, or is this an oversight in the standard (since this is admittedly a highly academic situation)?
The requirements of the call to the function object Deleter are specific on this as listed in the requirements of the std::unique_ptr<T>::reset() member.
From [unique.ptr.single.modifiers]/3, circa N4660 §23.11.1.2.5/3;
unique_ptr modifiers
void reset(pointer p = pointer()) noexcept;
Requires: The expression get_deleter()(get()) shall be well formed, shall have well-defined behavior, and shall not throw exceptions.
In general the type would need to be destructible. And as per the cppreference on the C++ concept Destructible, the standard lists this under the table in [utility.arg.requirements]/2, §20.5.3.1 (emphasis mine);
Destructible requirements
u.~T() All resources owned by u are reclaimed, no exception is propagated.
Also note the general library requirements for replacement functions; [res.on.functions]/2.
std::unique_ptr::reset does not invoke destructor directly, instead it invokes operator () of the deleter template parameter (which defaults to std::default_delete<T>). This operator is required to not throw exceptions, as specified in
23.11.1.2.5 unique_ptr modifiers [unique.ptr.single.modifiers]
void reset(pointer p = pointer()) noexcept;
Requires: The expression get_deleter()(get()) shall be well-formed, shall have >well-defined behavior, and shall not throw exceptions.
Note that shall not throw is not the same as noexcept though. operator () of the default_delete is not declared as noexcept even though it only invokes delete operator (executes delete statement). So this seems to be a rather weak spot in the standard. reset should either be conditionally noexcept:
noexcept(noexcept(::std::declval<D>()(::std::declval<T*>())))
or operator () of the deleter should be required to be noexcept to give a stonger guarantee.
Without having been in the discussions in the standards committee, my first thought is that this is a case where the standards committee has decided that the pain of throwing in the destructor, which is generally considered undefined behaviour due to the destruction of stack memory when unwinding the stack, was not worth it.
For the unique_ptr in particular, consider what could happen if an object held by a unique_ptr throws in the destructor:
The unique_ptr::reset() is called.
The object inside is destroyed
The destructor throws
The stack starts unwinding
The unique_ptr goes out of scope
Goto 2
There was to ways of avoiding this. One is setting the pointer inside of the unique_ptr to a nullptr before deleting it, which would result in a memory leak, or to define what should happen if a destructor throws an exception in the general case.
Perhaps this would be easier to explain this with an example. If we assume that reset wasn't always noexcept, then we could write some code like this would cause problems:
class Foobar {
public:
~Foobar()
{
// Toggle between two different types of exceptions.
static bool s = true;
if(s) throw std::bad_exception();
else throw std::invalid_argument("s");
s = !s;
}
};
int doStuff() {
Foobar* a = new Foobar(); // wants to throw bad_exception.
Foobar* b = new Foobar(); // wants to throw invalid_argument.
std::unique_ptr<Foobar> p;
p.reset(a);
p.reset(b);
}
What do we when p.reset(b) is called?
We want to avoid memory leaks, so p needs to claim ownership of b so that it can destroy the instance, but it also needs to destroy a which wants to throw an exception. So how and we destroy both a and b?
Also, which exception should doStuff() throw? bad_exception or invalid_argument?
Forcing reset to always be noexcept prevents these problems. But this sort of code would be rejected at compile-time.

Is it safe to use unique_ptr in an Exception class

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.

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.

C++ -- Difference between "throw new BadConversion("xxx")" and "throw BadConversion("xxx")"

// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html
class BadConversion : public std::runtime_error {
public:
BadConversion(std::string const& s)
: std::runtime_error(s)
{ }
};
inline std::string stringify(double x)
{
std::ostringstream o;
if (!(o << x))
throw BadConversion("stringify(double)");
// throw new BadConversion("stringify(double)");
return o.str();
}
[Q1] When we throw an exception in the function, what is the difference between throw new ClassName() and throw ClassName()?
[Q2] Which one is better?
Thank you
[A1] With throw new, you'll have to catch a pointer. The language doesn't specify in this case who is responsible for deallocation, so you'll have to establish your own convention (typically you'd make the catcher responsible). Without new, you'll want to catch by reference.
[A2] If you're in a framework that commonly throws pointers, you may want to follow suit. Else, throw without new. See also the C++ FAQ, item 17.14.
throw new ClassName() throws pointer to ClassName. You need to catch (ClassName * pc). It's not good idea. If new returns null or throws then you have null pointer when you catch or you have double exception.
throw ClassName() is usual way to throw an exception. You need to catch (const ClassName & pc).
throw new BadConversion(”xxx“) is creating a new object on the heap and throwing a pointer to it. That object will have to be deleted by the catch block. I can't think of a good reason why you would want to do that.
The other version is taken care of by RAII, use that.
Within your code base you should choose one method and stick to it for consistency.
If some of your code throws pointers and other libraries throws objects then your catch clauses may get a bit convoluted as you may need catches for both pointers and objects of the same type.
I personally prefer to throw objects rather than pointers (the main reason I choose this rather than pointers is that it mimics the standard library). Though it is quite feasible to throw pointers the question of ownership rears its ugly head. Who (if anybody) is responsible for deleting the pointer?

A question related to deriving standard exception classes

/* user-defined exception class derived from a standard class for exceptions*/
class MyProblem : public std::exception {
public:
...
MyProblem(...) { //special constructor
}
virtual const char* what() const throw() {
//what() function
...
}
};
...
void f() {
...
//create an exception object and throw it
throw MyProblem(...);
...
}
My question is why there is a "const throw()" after what()?
Normally,if there is a throw() , it implies that the function before throw()
can throw exception.However ,why there is a throw here?
Empty braces in "throw()" means the function does not throw.
The const is a separate issue to throw().
This indicates that this is a const method. Thus a call to this method will not change the state of the object.
The throw() means the method will not throw any exceptions.
To the USER of this method, the method will only return through normal means and you do not need to worry about the call generating exceptions.
To the IMPLEMENTER of the method there is more to worry about.
Unlike Java this is not a compile time constraint but a runtime constraint. If the implementer writes the function so that it accidentally throws an exception out of the method then the runtime will stop the application dead (no unwinding of the stack no destructors etc).
But the convention is that the implementer will take the extra precautions to catch all internal exceptions.
PS
You may want to derive from std::runtime_error
(From Comment#onebyone.livejournal.com): Not quite.
The no throw specifier is actively used. It is an indication of exception safety demonstrates that the method provides the no throw guarantee
On the other hand the other exception specifiers are not used because they are too dangerous. If you get them wrong it causes an application termination via (std::unexpected). The default action is application termination without unwinding the stack and without cleaning up using object destructors. In MHOP this is hardly ever desirable.
The const qualifies the function what(), saying it does not modify the internal structure of the exception object.
The throw() means it doesn't throw an exception, either - as noted by OneByOne and Checkers.
The two words are largely unrelated, even though they appear right next to each other in the signature.