令人惊讶的是,我无法通过谷歌搜索和搜索SO找到答案(SO上有很多类似的问题,但与其他语言相关)。
我怀疑答案是
no
。如果是这样,就会有明显的不便,例如
try
{
std::string fname = constructFileName(); // can throw MyException
ofstream f;
f.exceptions(ofstream::failbit | ofstream::badbit);
f.open(fname.c_str());
// ...
}
catch (ofstream::failure &e)
{
cout << "opening file " << fname << " failed\n"; // fname is not in the scope
}
catch (MyException &e)
{
cout << "constructing file name failed\n";
}
如果我的假设是正确的,你如何处理这个问题?我猜是通过将
std::string fname;
移出 try
来实现的?
我知道范围是由
{}
块定义的,但这似乎是一个合理的情况,嗯,例外。是不是抛出异常就无法完整构造对象的原因?
块是否共享catch
块的范围?try
没有。
你如何处理这个问题? 我猜是通过将
移出std::string fname;
来实现的?try
是的。
我知道范围是由
块定义的,但这似乎是一个合理的情况,嗯,例外。是不是抛出异常就无法完整构造对象的原因?{}
C++ 最不需要的就是更复杂的规则和规则的例外。 :-)
有一个明显的原因:您不能信任在 try 块内创建的对象的状态。 那里的代码被异常中断了,它们的构造函数甚至可能还没有运行。
虽然 James 的帖子正确回答了您的问题,但它没有提供通常的解决方法:
swap
。假设 constructFileName()
返回 std::string
而不是 char const*
,以下是惯用的:
std::string fname;
try
{
constructFileName().swap(fname); // can throw MyException
std::ofstream f;
f.exceptions(std::ios_base::failbit | std::ios_base::badbit);
f.open(fname.c_str());
// ...
}
catch (std::ios_base::failure &e)
{
std::cout << "opening file " << fname << " failed\n";
}
catch (MyException &e)
{
std::cout << "constructing file name failed\n";
}
它们超出了范围。这是因为如果你声明一个对象并尝试初始化它,而你初始化它的方式抛出异常,它就会被捕获。