如何捕获构造函数异常? 我有一个C++类,它从构造函数上抛出一个异常。如何分配此类的本地实例(不使用new)并处理任何可能的异常,同时使try块范围尽可能小 本质上,我在寻找下面的java成语的C++等价: boolean foo() { Bar x; try { x = new Bar(); } catch (Exception e) { return false; } x.doSomething(); return true; }

如何捕获构造函数异常? 我有一个C++类,它从构造函数上抛出一个异常。如何分配此类的本地实例(不使用new)并处理任何可能的异常,同时使try块范围尽可能小 本质上,我在寻找下面的java成语的C++等价: boolean foo() { Bar x; try { x = new Bar(); } catch (Exception e) { return false; } x.doSomething(); return true; },c++,constructor,exception-handling,C++,Constructor,Exception Handling,我不想捕获x.doSomething(),中的异常,只捕获构造函数 我想我要寻找的是一种分离x的声明和初始化的方法 不使用堆分配和指针是否可以实现这一点?您必须在 bool foo() { std::unique_ptr<Bar> x; try { x = std::make_unique<Bar>(); } catch (const BarConstructorException& e) { return

我不想捕获
x.doSomething()
中的异常,只捕获构造函数

我想我要寻找的是一种分离
x
的声明和初始化的方法


不使用堆分配和指针是否可以实现这一点?

您必须在

bool foo() {
    std::unique_ptr<Bar> x;
    try {
        x = std::make_unique<Bar>();
    } catch (const BarConstructorException& e) {
        return false;
    }
    x->doSomething();
    return true;
}

通常,如果希望避免堆分配,则不能将局部变量的声明与其定义分开。因此,如果要将所有功能组合在一个函数中,则必须使用
try/catch
块围绕
x
的整个范围:

boolean foo() {
    try {
        Bar x;
        x.doSomething();
    } catch (Exception e) {
        return false;
    }
    return true;
}

是的,如果您将所有代码都放在
try
子句中,例如通过使用(以避免不必要的嵌套和作用域):

或者在
try
子句中调用另一个执行实际工作的函数:

void real_foo()
{
    Bar x;
    x.doSomething();
}

bool foo() try
{
    real_foo();
    return true;
}
catch (std::exception const& e)
{
    return false;
}
请注意,在构造函数中抛出异常通常不是一个好主意,因为这样会停止对象的构造,并且不会调用其析构函数


正如Holt所指出的,这还将捕获来自
doSomething
调用的异常。有两种解决方法:

  • 简单而标准的方法是:使用指针

  • 使用两阶段构造:拥有一个不能抛出异常的默认构造函数,然后调用一个可以抛出异常的特殊“构造”函数

  • 第二种方法在C++标准化之前是常见的,在代码中广泛使用。这已经不常见了,因为使用指针来实现这一点要简单得多,特别是现在有了好的智能指针。在现代C++中,我真的不推荐第二种方法。 当然,最简单的方法是确保构造函数根本不能抛出异常,或者如果抛出任何异常,那么它们的性质就是程序无论如何都不能继续,并且程序被终止。正如在您的问题的评论中提到的,C++中的异常是昂贵的,然后我们也有废弃的构造问题,并且在C++中使用的所有异常只应该在特殊情况下完成。C++不是java,你不应该把它当作这样的语言,即使两种语言都有相似的构造。
    如果您仍然想从构造函数中抛出异常,实际上还有第三种方法可以只捕获这些异常:使用上面的一个代码示例,只抛出那些
    doSomething
    永远无法抛出的特定异常,然后只捕获这些特定构造函数。

    否。从您的java示例中,您必须在以下两种可能性中进行选择:

    没有指针:

    bool foo() {
        try {
            Bar x;
            x.doSomething();
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    
    bool foo() {
        Bar* x = nullptr;
        try {
            x = new Bar();
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
    
        delete x; // don't forget to free memory
    
        return true;
    }
    
    #include <memory>
    
    bool foo() {
        std::unique_ptr<Bar> x;
        try {
            x = new Bar();               // until C++14
            x = std::make_unique<Bar>(); // since C++14
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
        return true;
    }
    
    使用指针:

    bool foo() {
        try {
            Bar x;
            x.doSomething();
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    
    bool foo() {
        Bar* x = nullptr;
        try {
            x = new Bar();
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
    
        delete x; // don't forget to free memory
    
        return true;
    }
    
    #include <memory>
    
    bool foo() {
        std::unique_ptr<Bar> x;
        try {
            x = new Bar();               // until C++14
            x = std::make_unique<Bar>(); // since C++14
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
        return true;
    }
    
    或使用托管指针:

    bool foo() {
        try {
            Bar x;
            x.doSomething();
        } catch (Exception e) {
            return false;
        }
        return true;
    }
    
    bool foo() {
        Bar* x = nullptr;
        try {
            x = new Bar();
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
    
        delete x; // don't forget to free memory
    
        return true;
    }
    
    #include <memory>
    
    bool foo() {
        std::unique_ptr<Bar> x;
        try {
            x = new Bar();               // until C++14
            x = std::make_unique<Bar>(); // since C++14
        } catch (Exception e) {
            return false;
        }
        x->doSomething();
        return true;
    }
    
    #包括
    布尔福(){
    std::唯一的ptr x;
    试一试{
    x=新条();//直到C++14
    x=std::make_unique();//自C++14
    }捕获(例外e){
    返回false;
    }
    x->doSomething();
    返回true;
    }
    
    <代码> > P>此java习语自从C++ > bar x以来,不能很好地翻译成C++;代码>将需要默认构造函数,即使您的实际构造函数需要传递参数

    我建议将这种语言打到这个程度-扩大
    try
    块就足够了-但是如果你真的想缩小范围,那么你可以使用函数并依靠返回值优化来避免值拷贝:

    Bar foobar()
    {
        try {
            return Bar();
        } catch (Exception& e){
            /* Do something here like throwing a specific construction exception
               which you intercept at the call site.*/
        }
    }
    
    但实际上,您可以在构造时抛出一个特定的异常,因此完全避免使用此函数方法。

    您可以从C++17使用:

    bool foo() {
        std::optional<Bar> x; // x contains nothing; no Bar constructed
        try {
            x.emplace();      // construct Bar (via default constructor)
        } catch (const Exception& e) {
            return false;
        }
        x->doSomething();     // call Bar::doSomething() via x (also (*x).doSomething() )
        return true;
    }
    
    bool-foo(){
    std::可选x;//x不包含任何内容;未构造任何条
    试一试{
    x、 emplace();//构造栏(通过默认构造函数)
    }捕获(常量异常和e){
    返回false;
    }
    x->doSomething();//通过x调用Bar::doSomething()(也(*x).doSomething())
    返回true;
    }
    
    在修订后的问题中,OP增加了以下要求:

    我不想捕获
    x.doSomething()
    中的异常,只捕获[局部变量的]构造函数

    翻译Java代码的简单方法

    boolean foo() {
        Bar x;
        try {
            x = new Bar();
        } catch (Exception e) {
            return false;
        }
        x.doSomething();
        return true;
    }
    

    ……到C++,则使用<代码> optalal><代码>类(如Barton Nackmann <代码> FalLabeB/EXCOR>,<代码> Boo::可选< <代码>或C++ 17代码>:STD::可选< <代码> < /P>


    如果您不喜欢上述方法,则始终可以使用动态分配的
    Bar
    实例,例如,使用
    std::unique_ptr
    进行保证的清理,但这具有动态分配的一般开销。在Java中,大多数对象都是动态分配的,所以这似乎不是一个严重的缺点。但是在C++中,大多数对象都是超快堆栈,所以动态分配是一个非常慢的操作,与普通操作相比,因此动态分配的概念简单性必须与之相比。将所有内容放在try块内的成功路径上。StyyToLeLe:如果我不想从例如代码> x.DOMMETHONSE()/CUD>中捕获异常,只有构造函数中的例外情况“@安德烈孙”使用不同的异常,或者在内部异常块中放置<代码> x.DOMMETHOTHEN(/CUB>)> C++异常非常昂贵(对于C++速度瘾君子)。与Java不同,您不应该一开始就随意地抛出它们。如果您已经这样做了,那么就重新设计您的异常层次结构,并从
    x.doSomething()重新抛出内容您知道要捕获什么异常吗?内存分配可能会失败,构造函数代码可能会失败…您可能需要添加一个