从构造函数中捕获异常意味着我的实例后来超出了范围

问题描述 投票:3回答:4

我有一个类,其构造函数可能会抛出异常。这里有一些代码可以捕获异常:

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

但是当然,在try / catch之后没有代码可以看到instance,因为它现在超出了范围。解决这个问题的一种方法是分别声明和定义instance

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

除了我的类没有适当的零参数构造函数。实际上,这里的情况就是这样一个构造函数甚至有意义的唯一一个:MyClass对象是不可变的,因为它的数据成员在构造之后都没有变化。如果我要添加一个零参数构造函数,我需要引入一些像is_initialized_这样的实例变量,然后在继续之前检查每个方法以确保该变量是true。对于这样一个简单的模式来说,这似乎太过冗长。

处理这种事情的惯用方法是什么?我是否需要将其填充并允许在初始化之前声明我的类的实例?

c++ constructor exception-handling scope try-catch
4个回答
11
投票

您应该在try块中执行您需要执行的所有操作:

try {
    MyClass instance(3, 4, 5);

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

毕竟,只有在try区块内才能成功创建instance,因此可以使用。

我想知道你的catch块是否真的处理异常。如果你无法解决问题,你应该让它传播。


3
投票

使用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...

2
投票

您可以使用捕获异常的通用辅助函数和未来的std::optional(或boost::optional)来表示实例的成功或失败的创建:

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

基本上使用这个:

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

instance现在是optional<MyClass>。要测试结果并将实例与错误情况分开可用性也很简单:

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
}

当然,异常信息将以这种方式丢失,但您可以选择不太通用的函数,并根据需要在catch-block中添加一些日志记录。


1
投票

Remy的答案的变体,但使用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...
© www.soinside.com 2019 - 2024. All rights reserved.