【问题标题】:C++ bad_alloc exceptionC++ bad_alloc 异常
【发布时间】:2012-02-13 16:43:50
【问题描述】:

我试图捕获bad_alloc 异常以证明使用了析构函数。

这是我的对象:

#include "Obj.h"
#include<iostream>
using namespace std;

Obj::Obj() {
d = new double[200000000];
}
Obj::~Obj() {
cout << "destroyed \n";
}

以及主要方法:

#include "Obj.h"
#include <iostream>
using namespace std;
int main(){
Obj* ptr[1000000];
try{
    for(int i=0; i<1000; i++){
        ptr[i] = new Obj();
    }
} catch(bad_alloc){
    cout<<"EXCEPTION";
}
}

我的程序没有捕获异常,而是停止并尝试在线寻找解决方案(Windows)。 为什么会这样?

编辑 我现在得到了异常,但我应该证明在抛出异常之前使用了析构函数。我该怎么做?

【问题讨论】:

  • 在线解决方案?那是什么?
  • 我猜是在 Visual Studio 中在线命名的解决方案。
  • @VJovic:在 Windows 上,当程序导致 Windows 能够检测到的某些类别的错误时,会弹出一个对话框,询问您是否希望 Windows 在线寻找解决方案(可能程序有错误并且有一个已知的修复方法)。
  • Obj 析构函数永远不会被这个程序调用。
  • @BenjaminLindley 感谢您解释我的意思。

标签: c++ windows exception


【解决方案1】:

在您开始动态分配对象之前,问题就出现了。如果您在附加调试器的情况下运行程序,您将看到程序由于堆栈溢出而终止。为什么?

Obj* ptr[1000000];

您不能将这么大的对象声明为具有自动存储持续时间。当输入main时,它会尝试为这个对象分配堆栈空间,但失败了,导致抛出堆栈溢出结构化异常。您的应用程序不会处理此异常,因此运行时会终止程序。

但是请注意,Obj 析构函数永远不会被您的程序调用。当您使用new 动态分配对象时,您有责任使用delete 销毁它。由于您从未调用delete 来销毁您创建的对象,因此它们永远不会被销毁。

如果您要使用 std::vector&lt;std::unique_ptr&lt;Obj&gt;&gt; 代替(或者,就此而言,仅使用 std::vector&lt;Obj&gt;),您会看到将为每个完全创建的 Obj 对象调用析构函数。

【讨论】:

  • 谢谢。我现在得到了例外。请查看问题更新。
  • 我认为 Windows 上的默认堆栈分配是 1Mb,所以理论上这应该适合......虽然可能不适合所有其他东西。
  • std::vector&lt;std::unique_ptr&lt;Obj&gt;&gt; 将为 c++03 生成编译器错误,大多数编译器仍然依赖它。
  • @Benj:我不知道默认情况下它是什么(这是其中之一,如果你不得不问,你做错了,释义雷蒙德陈)。也就是说,1MB 不足以存储一百万个四(或八)字节指针的连续数组。
  • @Mr.TAMER:大多数编译器。
【解决方案2】:

请记住,您正在尝试使用您的 ptr 数组在堆栈上存储一个非常大的数组......您的问题很可能是您已经溢出了之前为您的应用程序分配的堆栈的默认大小operator new 可能会失败,但会出现内存不足的异常。

【讨论】:

  • 为 1000000 分配空间然后只使用 1000 没有多大意义。更不用说每个对象都会尝试在 new 中分配 1.6GB (200M*8) - 我不确定你是否能够分配其中一个。
【解决方案3】:

我将您的所有代码粘贴到一个文件中,稍微增加了整数常量,完成了 Obj 的类定义,并通过一些调试重新运行了您的代码。在 64 位 unix 服务器上,它会在尝试执行 Obj 构造函数时正确打印出“异常”。

#include<iostream>
using namespace std;

struct Obj {
Obj() {
d = new double[20000000000000000LL];
}
~Obj() {
cout << "destroyed \n";
}

double* d;
};

int main(){
Obj* ptr[1000000];
try{
    for(int i=0; i<1000; i++){
        ptr[i] = new Obj();
        cout<<"bah!"<<endl;
    }
} catch(bad_alloc){
    cout<<"EXCEPTION";
}
cout<<"Done."<<endl;
}

[jhumphreys@suoserv ~]$ g++ so2.cpp
[jhumphreys@suoserv ~]$ ./a.out
EXCEPTIONDone.
[jhumphreys@suoserv ~]$

【讨论】:

  • 有没有办法在 Windows 上获取异常?
  • 我没有可用的 Visual Studio 环境 - 但我假设如果您在没有安装 Visual Studio 及其调试工具的计算机上运行您创建的可执行文件,那么您会当您编写程序时,请按照您的预期查看输出。从记忆中我很确定调试器功能是 Windows 的一个插件,一旦你开始安装开发工具就会启用。
  • 这与过度保护无关。当你用完堆栈空间时,你就用完了堆栈空间。
  • 是的,我删除了那个短语,因为它可能是假的。不过,我怀疑他是否耗尽了堆栈空间,他的 Obj* 数组并没有太大,其他一切都是基于堆的。
  • @w00te :它非常大......在 32 位平台上几乎是 4MB,在 64 位平台上是 8MB......我不确定默认的 Win32 堆栈分配是什么,但除非您特别要求,否则我认为它不是每个进程 4MB。在 Linux 64 位上,我相信 8MB 是默认限制。
猜你喜欢
  • 2019-06-22
  • 2021-11-12
  • 1970-01-01
  • 2023-03-29
  • 1970-01-01
  • 1970-01-01
  • 2014-12-06
  • 1970-01-01
  • 2020-04-09
相关资源
最近更新 更多