在try-catch块之外访问变量

时间:2015-12-15 11:52:13

标签: c++ c++11

我有以下代码:

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的唯一方法吗?

3 个答案:

答案 0 :(得分:10)

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

try
{
    ClassA a = ClassA(s);

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

原因是atry块引用对象之后超出范围,之后是未定义的行为(如果你有指向它的位置)。

如果您关注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); }

public partial class TestForm : Form
{
    public TestForm()
    {
        InitializeComponent();
        this.Load += Test_Load;
    }

    private void Test_Load(object sender, EventArgs e)
    {
        try
        {
            XmlDocument doc1 = new XmlDocument();
            doc1.Load("file1.xml");
            XmlDocument doc2 = new XmlDocument();
            doc2.Load("file2.xml");

            trvLeft.Nodes.Clear();
            trvRight.Nodes.Clear();
            trvLeft.Nodes.Add(new TreeNode("File 1"));
            trvRight.Nodes.Add(new TreeNode("File 2"));
            TreeNode tlNode = new TreeNode();
            TreeNode trNode = new TreeNode();
            tlNode = trvLeft.Nodes[0];
            trNode = trvRight.Nodes[0];
            AddNode(doc1.DocumentElement, doc2.DocumentElement, tlNode, trNode);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }


        var childrensLeft = trvLeft.Nodes[0].Nodes[0].Nodes;
        var childrensRight = trvRight.Nodes[0].Nodes[0].Nodes;
        for (int i = 0; i < Math.Min(childrensLeft.Count, childrensRight.Count); i++)
        {
            if (childrensRight[i].Text != childrensLeft[i].Text)
            {
                //childrensLeft[i].ForeColor = Color.Red;
                //childrensRight[i].ForeColor = Color.Red;
                childrensLeft[i].Nodes.Add("Something to left");
                childrensRight[i].Nodes.Add("Something to right");
            }
        }
        trvLeft.ExpandAll();
        trvRight.ExpandAll();
    }
    private void AddNode(XmlNode leftXmlNode, XmlNode rightXmlNode, TreeNode leftNode, TreeNode rightNode)
    {
        //XmlNode xNode;
        TreeNode tlNode;
        TreeNode trNode;
        XmlNodeList lnodeList;
        XmlNodeList rnodeList;
        int i;

        if (leftXmlNode.HasChildNodes && rightXmlNode.HasChildNodes)
        {
            lnodeList = leftXmlNode.ChildNodes;
            rnodeList = rightXmlNode.ChildNodes;
            for (i = 0; i <= Math.Min(lnodeList.Count, rnodeList.Count) - 1; i++)
            {
                var lNode = leftXmlNode.ChildNodes[i];
                var rNode = rightXmlNode.ChildNodes[i];
                leftNode.Nodes.Add(new TreeNode(lNode.Name));
                tlNode = leftNode.Nodes[i];
                rightNode.Nodes.Add(new TreeNode(rNode.Name));
                trNode = rightNode.Nodes[i];
                AddNode(lNode, rNode, tlNode, trNode);
            }
        }
        else
        {
            leftNode.Text = (leftXmlNode.OuterXml).Trim();
            rightNode.Text = (rightXmlNode.OuterXml).Trim();
        }
    }
}

答案 1 :(得分:5)

您可以使用某种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.
}

答案 2 :(得分:2)

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

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

另一种方法是使用std::optional。这与使用指针的概念相同,但它使用自动分配,因此您不太可能创建内存泄漏。这是 experimental 状态;如果您的编译器没有boost::optional,则可以使用std::experimental::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();

我想重申一点,虽然这有点意大利面风格,但设计代码的方式不同,所以你不能不断测试建筑是成功还是失败。< / p>

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