C++ 为什么';t catch块是否共享try块的范围?

C++ 为什么';t catch块是否共享try块的范围?,c++,exception-handling,error-handling,try-catch,C++,Exception Handling,Error Handling,Try Catch,令人惊讶的是,我无法通过谷歌搜索SO找到答案(SO上有很多类似的问题,但与其他语言有关) 我怀疑答案是否定的。如果是,则会带来明显的不便,例如: try { std::string fname = constructFileName(); // can throw MyException ofstream f; f.exceptions(ofstream::failbit | ofstream::badbit); f.open(fname.c_str()); // ... }

令人惊讶的是,我无法通过谷歌搜索SO找到答案(SO上有很多类似的问题,但与其他语言有关)

我怀疑答案是否定的。如果是,则会带来明显的不便,例如:

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=constructFileName();//可以抛出MyException
流f;
f、 异常(ofstream::failbit | ofstream::badbit);
f、 open(fname.c_str());
// ...
}
捕获(流::失败和e)
{
库特
catch
块是否共享
try
块的范围

没有

如何处理这个问题?我想,通过将
std::string fname;
移出
try

我知道范围是由
{}
块定义的,但这似乎是异常的合理情况。如果抛出异常,对象不能完全构造的原因是什么


最后一个C++需要的是更复杂的规则和规则的异常。---/p>它们超出了范围。这是因为如果声明一个对象并尝试初始化它,而初始化它的方式会引发异常,则会被捕获。

有一个明显的原因:您不能信任创建的对象的状态。ide尝试块。那里的代码被异常中断,它们的构造函数可能还没有运行。

虽然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";
}
std::string fname;
尝试
{
constructFileName().swap(fname);//可以引发MyException
流f的std::;
f、 异常(std::ios_base::failbit | std::ios_base::badbit);
f、 open(fname.c_str());
// ...
}
捕获(标准::ios\U基::失败和e)
{

std::不能当场正确。如果在
中尝试{aaa;bb;}
A
的构造函数抛出,则
A
B
都不能合理地在范围内。除此之外,编译器可能不知道
constructFileName()
可以抛出
of stream::failure
。如果
fname
在第一个
catch
块中仍在作用域内,请考虑它何时被销毁-在catch执行之后,但有条件地取决于抛出的来源。是的。您可以尝试告诉编译器每个函数抛出什么,但我不太喜欢对象其生存期和作用域取决于
constructFileName()的异常规范
。销毁在抛出点之前创建的所有内容要干净得多,然后处理catch子句。谢谢。为什么
swap
在这里比赋值好?如果在赋值过程中抛出异常,这会使
fname
处于未定义状态吗?@davka:对于C++0x之前的编译器,
运算符=
会导致出现这种情况在赋值过程中有两个数据副本,这是非常不必要的低效,而使用
swap
时,最多会有一个数据副本。对于C++0x编译器,在这种情况下,这两种方式都无关紧要,因为
constructFileName
的结果将是一个右值,因此会移动到
fname
(同时确保最多有一份数据副本)简言之:
swap
在除尖端编译器外的所有编译器上都更有效。我不认为这是显而易见的。例如,在同样具有构造函数的python中,try块没有定义新的作用域。@Étienne这不是一个合适的比较。在python中,您引用的变量是在运行时动态确定的。因此,如果没有构造变量,甚至没有名字。在C++中,情况并非如此。