Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.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++;我不工作了? 我刚刚开始用C++编写RAII,并设置了一个小测试用例。要么我的代码很混乱,要么RAII不工作!(我想是前者吧)_C++_Exception_Raii - Fatal编程技术网

C++;我不工作了? 我刚刚开始用C++编写RAII,并设置了一个小测试用例。要么我的代码很混乱,要么RAII不工作!(我想是前者吧)

C++;我不工作了? 我刚刚开始用C++编写RAII,并设置了一个小测试用例。要么我的代码很混乱,要么RAII不工作!(我想是前者吧),c++,exception,raii,C++,Exception,Raii,如果我跑步: #include <exception> #include <iostream> class A { public: A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; } ~A() { std::cout << "A " << i_ << " destructe

如果我跑步:

#include <exception>
#include <iostream>
class A {
public:
    A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; }
    ~A() { std::cout << "A " << i_ << " destructed" << std::endl; }
private:
    int i_;
};

int main(void) {
    A a1(1);
    A a2(2);
    throw std::exception();
    return 0;
}
如预期,但除此之外,我得到:

A 1 constructed
A 2 constructed
terminate called after throwing an instance of 'std::exception'
  what():  std::exception
Aborted
因此,即使我的对象超出范围,它们也不会被破坏。这不是RAII的全部基础吗


非常感谢指点和更正

在main中有一个未处理的异常,这意味着要终止的调用。试试这个:

int main(void)
{
    try
    {
        A a1(1);
        A a2(2);
        throw std::exception();
        return 0;
    }
    catch(const std::exception & e)
    {
        return 1;
    }


}

您没有正确处理异常,因此您的应用程序在对象超出范围之前退出

我要再解释一下。如果异常“冒泡”到主堆栈,则堆栈展开(编辑)。即使将代码移动到辅助函数也无法解决此问题。例:

      1 #include <exception>
      2 #include <iostream>
      3
      4 void test();
      5
      6 class A {
      7     public:
      8         A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; }
      9         ~A() { std::cout << "A " << i_ << " destructed" << std::endl; }
     10     private:    int i_;
     11 };
     12
     13
     14 int main(void) {
     15     test();
     16     return 0;
     17 }
     18
     19 void test(){
     20             A a1(1);
     21             A a2(2);
     22            throw std::exception();
     23 }
1#包括
2#包括
3.
4无效试验();
5.
6甲级{
7公众:

8A(内部一){Ii= i;STD::CUT< P>您没有异常处理程序。当发生这种情况时,标准称STD::终止调用,这又称为中止。参见C++编程语言第14.7节,第三版。

< P>问题是主< /C> >具有特殊状态。当从该异常抛出时,堆栈不能。有意义的是,应用程序只调用
std:terminate

这就有点道理了,为什么变量没有超出作用域。我们实际上没有离开声明它们的作用域。发生的事情可以被认为是等价的:

int main(void) {
  A a1(1);
  A a2(2);
  std::terminate();
}

(我相信在这种情况下是否调用析构函数是由实现定义的,因此在某些平台上,它将按照您的预期工作)

正如其他人所指出的,您有一个未捕获的异常,它调用terminate()。它是由实现定义的(参见标准,15.3第9段和15.5.1第2段)在这种情况下是否调用析构函数,并且实现中的定义显然是“否,它们不会”。(如果调用terminate()的原因不是引发没有处理程序的异常,则不会调用析构函数。)

由于调用了std::terminate,因此不会销毁a对象


std::terminate在未处理的异常从main泄漏时被调用。如果您将代码包装为try/catch(即使catch刚刚重新引发),您将看到预期的行为。

如果异常从main()逸出,则在堆栈解卷时,它是实现定义的

试一试


由于异常在到达main()时未被处理,因此会导致对std::terminate()的调用,本质上相当于

int main(void) {
  A a1(1);
  A a2(2);
  exit(1);
}
如果程序在超出范围之前终止,则不能保证调用析构函数。对于RAII中的另一个漏洞,请考虑:

int main(void) {
  A *a1 = new A(1);
}

其他人建议在
main()
中放置一个try/catch来处理这个问题,效果很好。出于某种原因,我发现很少使用的“函数try block”看起来更好,这让我感到惊讶(我认为它看起来太奇怪了)。但我认为它没有任何真正的优势:

int main(void) 
try
{
    A a1(1);
    A a2(2);
    throw std::exception();
    return 0;
}
catch (...) 
{
    throw;
}

有两个缺点是,由于它很少使用,许多开发人员在看到它时都会被抛出一个循环,如果考虑到这一点,VC6会被它卡住。

下面的代码可以工作

#include <exception> 
#include <iostream> 

class A { 
public: 
    A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; } 
    ~A() { std::cout << "A " << i_ << " destructed" << std::endl; } 
private: 
    int i_; 
}; 

void test() {
    A a1(1); 
    A a2(2); 
    throw std::exception(); 
} 

int main(void) { 
 try {
  test();
 } catch(...) {
 }
    return 0; 
} 
#包括
#包括
A类{
公众:

A(int i){i_=i;std::cout,所以在使用RAII时,我必须始终在try/catch中包装main?我认为main()是不同的。尝试将从main()调用的所有内容都放在一个函数中。不,仅当您执行可能引发异常的操作时。不“总是”,仅在main()中试着把代码移到一个单独的函数中,并将异常处理程序放在主程序中。你必须尝试{{} CasChh(),否则,当你到达最外层范围时,你就终止了。你也发现了C++中的一个错误!=)如果一个异常漏掉了主(),它是一个实现定义的天气,栈被解开。因此添加一个尝试{} catch(…){}。块到main,你就没事了。你的意思是不是?如果你没有尝试/捕获,即使你将代码移动到另一个函数,它也会冒泡到main并导致相同的问题。所以“main”一点也不特别。你对“未定义行为”的看法是错误的在没有标准的情况下,没有定义一个处理程序的行为,除了是否定义了堆栈是被定义的。改变的答案来反映这个。为什么要定义这个实现?如果构造函数总是被调用,它不是更有意义吗?C++有时候是愚蠢的……不是愚蠢的-实用的。析构函数(非构造函数)调用总是会限制EH和栈展开的方式。这可能是愚蠢的,但也是实用的。C++规范试图避免限制实现。理想地,他们希望能够在任何CPU和任何OS上创建符合C++实现标准。在OS和C++之间,他们不想太多地假设。你说的对,在现实世界中,如果他们没有把这个细节留给实现,那就太好了。我们现在知道了,但是在1998,当语言被标准化时,是否明显?他们不想把自己画成一个。corner@jalf:也许是吧是时候重新讨论这个问题了?@just:为了什么好处?可能还有一些实现只有在额外的自由度下才可能实现。此外,这会造成混乱(我的编译器实现了新的、严格的行为,还是还没有更新?)这也没什么大不了的,不是吗?第一次遇到这个问题可能会让人惊讶,但当它成为代码中的一个问题时,很容易发现和修复。实际上,您可以设置自己的终止函数,但我不知道它是否真的有用。嗯,可以使用它,比如,将终止记录到sp
int main(void) 
try
{
    A a1(1);
    A a2(2);
    throw std::exception();
    return 0;
}
catch (...) 
{
    throw;
}
#include <exception> 
#include <iostream> 

class A { 
public: 
    A(int i) { i_ = i; std::cout << "A " << i_ << " constructed" << std::endl; } 
    ~A() { std::cout << "A " << i_ << " destructed" << std::endl; } 
private: 
    int i_; 
}; 

void test() {
    A a1(1); 
    A a2(2); 
    throw std::exception(); 
} 

int main(void) { 
 try {
  test();
 } catch(...) {
 }
    return 0; 
}