访问 try-catch 块外部的变量

Access variable outside try-catch block

本文关键字:变量 外部 try-catch 访问      更新时间:2023-10-16

我有以下代码:

class ClassA
{
public:
    ClassA(std::string str);
    std::string GetSomething();
};
int main()
{
    std::string s = "";
    try
    {
        ClassA a = ClassA(s);
    }
    catch(...)
    {
        //Do something
        exit(1);
    }
    std::string result = a.GetSomething();
    //Some large amount of code using 'a' out there.
}

我希望最后一行可以访问a变量。鉴于 ClassA 没有默认构造函数ClassA()并且我不想使用指针,我如何实现这一目标?是将默认构造函数添加到ClassA的唯一方法吗?

你不能或不应该。相反,您可以在try块中使用它,如下所示:

try
{
    ClassA a = ClassA(s);
    std::string result = a.GetSomething();
}
catch(...)
{
    //Do something
    exit(1);
}

原因是,由于a在引用对象之后的try块之后超出了范围,这是未定义的行为(如果您有指向它所在位置的指针(。

如果您关心a.GetSomething或作业throw,您可以对此进行try-catch

try
{
    ClassA a = ClassA(s);
    try {
        std::string result = a.GetSomething();
    }
    catch(...) {
        // handle exceptions not from the constructor
    }
}
catch(...)
{
    //Do something only for exception from the constructor
    exit(1);
}
您可以使用

某种optional或仅使用std::unique_ptr

int main()
{
    std::string s = "";
    std::unique_ptr<ClassA> pa;
    try
    {
        pa.reset(new ClassA(s));
    }
    catch
    {
        //Do something
        exit(1);
    }
    ClassA& a = *pa; // safe because of the exit(1) in catch() block
    std::string result = a.GetSomething();
    //Some large amount of code using 'a' out there.
}

当然,只是扩展try块以包括a的使用是最简单的解决方案。

此外,如果您真的打算在失败时exit(1)或以其他方式中止程序,那么根本不要在这里放置try块。异常将向上传播,如果未捕获,则会中止程序。


一种替代方法是使用 std::optional .这与使用指针的概念相同,但它使用自动分配,因此不太可能创建内存泄漏。这目前处于实验状态;如果您的编译器没有std::experimental::optional,则可以改用boost::optional

#include <experimental/optional>
using std::experimental::optional;   
using std::experimental::in_place;
// ...
    optional<ClassA> a;
    try 
    {
        a = optional<ClassA>(in_place, s);
    }
    catch(...)
    {
         // display message or something
    }
    std::string result;
    if ( a )
        result = a->GetSomething();

我想重申一下,这有点意大利面风格,最好以不同的方式设计代码,这样您就不会不断测试构造是成功还是失败。

这要求ClassA可移动或可复制。in_place是一个特殊的参数,它为其余参数调用一个完美的转发构造函数。如果没有in_place,您只能给出一个实际的ClassA作为构造函数参数,它不考虑隐式转换为ClassA。 (这就是optional避免复制构造和从相同类型的对象进行列表初始化之间的歧义的方式(。