简体   繁体   中英

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM