Catching exceptions from a constructor means that my instance is out of scope afterward

前端 未结 4 1393
北海茫月
北海茫月 2020-12-11 21:18

I have a class whose constructor may throw an exception. Here’s some code that will catch the exception:

try {
    MyClass instance(3, 4, 5);
}
catch (MyClas         


        
相关标签:
4条回答
  • 2020-12-11 21:37

    Dynamically allocate the instance using new:

    std::unique_ptr<MyClass> instance;
    try
    {
        instance.reset(new MyClass(3, 4, 5));
    }
    catch (const MyClassException& ex)
    {
        std::cerr << "There was an error creating the MyClass." << std::endl;
        return 1;
    }
    // use instance as needed...
    
    0 讨论(0)
  • 2020-12-11 21:45

    A variant of Remy's answer, but saving a dynamic allocation using std::optional:

    std::optional<MyClass> instance_opt;
    try {
        // could use `instance = MyClass(3, 4, 5)`, but that requires you to write a move constructor
        instance_opt.emplace(3, 4, 5);
    }
    catch (const MyClassException& ex) {
        std::cerr << "There was an error creating the MyClass." << std::endl;
        return 1;
    }
    MyClass& instance = *instance_opt;
    // use instance as needed...
    
    0 讨论(0)
  • 2020-12-11 22:00

    You should be doing everything you need to do inside the try block:

    try {
        MyClass instance(3, 4, 5);
    
        // Use instance here
    }
    catch (MyClassException& ex) {
        cerr << "There was an error creating the MyClass." << endl;
        return 1;
    }
    

    After all, it is only within the try block that instance has been successfully created and so can be used.

    I do wonder whether your catch block is really handling the exception. If you can't do anything to resolve the situation, you should be letting it propagate.

    0 讨论(0)
  • 2020-12-11 22:02

    You could use a generic helper function that catches exceptions and the future std::optional (or boost::optional) to signal the successful or failed creation of the instance:

    template< typename T, typename... Args >
    std::optional< T > try_make( Args&&... args )
    {
        try {
            return T{ std::forward< Args >( args )... };
        }
        catch( ... ) {
            return {};
        }
    }
    

    Using basically this:

    auto instance = try_make< MyClass >(3, 4, 5);
    

    Where instance is now an optional<MyClass>. To test the result and separate availablity of the instance from the error case is also simple:

    if( auto instance = try_make< MyClass >( 3, 4, 5 ) ) {
        // use *instance, but this code is *not* in the try/catch block!
    }
    else {
        // creating the instance failed
    }
    

    Of course the exception information will be lost this way, but you could go for a less generic function and add some logging in the catch-block depending on your needs.

    0 讨论(0)
提交回复
热议问题