我有以下代码:
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
的唯一方法吗?
答案 0 :(得分:10)
你不能或不应该。相反,您可以在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);
}
:
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
避免复制构造和列表初始化从同一类型的对象之间的歧义的方式。)