Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 函数try块的用途是什么?_C++_Exception_Exception Handling_Function Try Block - Fatal编程技术网

C++ 函数try块的用途是什么?

C++ 函数try块的用途是什么?,c++,exception,exception-handling,function-try-block,C++,Exception,Exception Handling,Function Try Block,可能重复: 此代码在类UseResources中构造Dog对象时抛出int异常。int异常被正常的try catch块捕获,代码输出: Cat() Dog() ~Cat() Inside handler 输出是相同的 Cat() Dog() ~Cat() Inside handler i、 最终结果完全相同 那么,函数try块的用途是什么?想象一下,如果用户资源是这样定义的: class UseResources { class Cat *cat;

可能重复:

此代码在类
UseResources
中构造
Dog
对象时抛出
int
异常。
int
异常被正常的
try catch
块捕获,代码输出:

Cat()  
Dog()  
~Cat()  
Inside handler

输出是相同的

Cat()  
Dog()  
~Cat()  
Inside handler 
i、 最终结果完全相同


那么,
函数try块的用途是什么?

想象一下,如果
用户资源
是这样定义的:

class UseResources
{
    class Cat *cat;
    class Dog dog;

    public:
    UseResources() : cat(new Cat), dog() { cout << "UseResources()" << endl; }
    ~UseResources() { delete cat; cat = NULL; cout << "~UseResources()" << endl; }
};
为了更全面地回答您的问题,构造函数中函数级try/catch块的目的就是专门进行这种清理。功能级别的try/catch块不能吞咽异常(常规块可以)。如果他们捕获了某个内容,当他们到达catch块的末尾时,他们将再次抛出该内容,除非您使用
throw
显式地重新抛出该内容。您可以将一种类型的异常转换为另一种类型的异常,但您不能简单地接受它并像没有发生一样继续进行

这就是为什么应该使用值和智能指针而不是裸指针(即使作为类成员)的另一个原因。因为,就像你的例子一样,如果你只有成员值而不是指针,你就不必这么做。使用裸指针(或RAII对象中未管理的其他形式的资源)强制执行此类操作

请注意,这几乎是函数try/catch块的唯一合法使用


不使用函数try块的更多原因。上述代码被巧妙地破坏了。考虑这一点:

class Cat
{
  public:
  Cat() {throw "oops";}
};
那么,
UseResources
的构造函数中会发生什么呢?显然,表达式
newcat
将抛出。但这意味着,
cat
从未初始化过。这意味着
delete cat
将产生未定义的行为

您可以尝试使用复杂的lambda来纠正此问题,而不仅仅是
new Cat

UseResources() try
  : cat([]() -> Cat* try{ return new Cat;}catch(...) {return nullptr;} }())
  , dog()
{ cout << "UseResources()" << endl; }
catch(...)
{
  delete cat;
  throw;
}

简言之,将函数级try块视为严重的代码气味。

普通函数try块的作用相对较小。它们几乎与体内的试块相同:

int f1() try {
  // body
} catch (Exc const & e) {
  return -1;
}

int f2() {
  try {
    // body
  } catch (Exc const & e) {
    return -1;
  }
}
唯一的区别是函数try块位于稍大的函数作用域中,而第二个构造位于函数体作用域中——前者只看到函数参数,后者也看到局部变量(但这并不影响try块的两个版本)

唯一有趣的应用程序出现在构造函数try块中:

Foo() try : a(1,2), b(), c(true) { /* ... */ } catch(...) { }
这是捕获其中一个初始值设定项异常的唯一方法。您无法处理异常,因为整个对象构造仍然必须失败(因此,无论您是否愿意,都必须以异常退出catch块)。但是,这是专门处理初始值设定项列表中异常的唯一方法

这有用吗?可能不会。构造函数try块和以下更典型的“初始化为null并赋值”模式之间基本上没有区别,这本身就很糟糕:

Foo() : p1(NULL), p2(NULL), p3(NULL) {
  p1 = new Bar;
  try {
    p2 = new Zip;
    try {
      p3 = new Gulp;
    } catch (...) {
      delete p2;
      throw;
    }
  } catch(...) {
    delete p1;
    throw;
  }
}
正如你所看到的,你有一个无法维护,无法缩放的混乱。构造函数try块会更糟糕,因为您甚至无法知道已经分配了多少个指针。因此,只有当您有两个可泄漏的分配时,它才真正有用更新:由于阅读,我被提醒事实上您根本不能使用catch块来清理资源,因为引用成员对象是未定义的行为。So[结束更新]


简而言之:它是无用的。

复制的复制的复制的复制的…这是c++11吗?我从没见过before@VJovic我不知道这种语言是什么时候引入的。但它不是新的。@VJovic它是C++03。几乎没用过。这就是你要找的,@Xeo。可能的副本请参见。有趣。到目前为止,我所看到的关于函数try的示例中没有一个会阻止这种清理功能。但是在你的例子中,程序无论如何都会中止,那么这个特性有什么大不了的呢?如果操作系统真的要这样做,清理的目的是什么?异常处理并不是解决故障,而是更优雅地处理故障。此功能可帮助您优雅地释放资源。一个实际的例子可能是一个客户端崩溃,并使用它来释放服务器资源,这样它就不会让其他客户端无法操作。@AJG85但是
terminate()
将始终使用函数try块调用,在这种情况下,操作系统将释放任何资源。这不是真的吗?@user1042389:不,不会的<代码>捕获
仅在异常是功能级别的情况下自动重新调用异常。函数中的
捕获
可以选择是否重新引发异常。如果没有,则在
catch
块结束后继续执行。@nicolas我认为您的代码不安全:如果
new Cat
抛出异常,则catch块也将执行。在这里,您对包含垃圾的指针调用delete。这个指针可能包含一个有效的内存地址,这将导致坏的程序崩溃。“它是无用的。”当然,除非你想转换异常。
class UseResources
{
    unique_ptr<Cat> cat;
    Dog dog;

    public:
    UseResources() : cat(new Cat), dog() { cout << "UseResources()" << endl; }
    ~UseResources() { cout << "~UseResources()" << endl; }
};
int f1() try {
  // body
} catch (Exc const & e) {
  return -1;
}

int f2() {
  try {
    // body
  } catch (Exc const & e) {
    return -1;
  }
}
Foo() try : a(1,2), b(), c(true) { /* ... */ } catch(...) { }
Foo() : p1(NULL), p2(NULL), p3(NULL) {
  p1 = new Bar;
  try {
    p2 = new Zip;
    try {
      p3 = new Gulp;
    } catch (...) {
      delete p2;
      throw;
    }
  } catch(...) {
    delete p1;
    throw;
  }
}