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;
}