在构造函数中捕获内存分配错误?

时间:2011-02-21 19:03:16

标签: c++

我有时需要一个C ++类来分配动态内存。由于这可能会失败,我需要检测何时无法分配内存。通常,我这样做,如下例所示,即。我没有在构造函数中分配内存,但是有一个单独的方法,可以捕获bad_alloc异常。

有没有办法在构造函数中分配内存并捕获异常?

try {
  my_class my_instance;
}
catch ...

不起作用,因为my_instance的范围仅限于try阻止。

这是一个最小的例子:

#include <iostream>

class my_class {
private:
  char * data;

public:
  my_class () {
    data = NULL;
  }

  ~my_class () {
    delete [] data;
  }

  void init () {
    data = new char [10000000000];
  }

  void write (int x) {
    data[x] = 1;
  }
};

int main() {
  my_class my_instance;
  try {
    my_instance.init();
  }
  catch (std::bad_alloc&) {
    std::cout << "Memory overflow.\n";
    return 1;
  }

  my_instance.write(10);

  std::cout << "OK.\n";
  return 0;
}

5 个答案:

答案 0 :(得分:3)

不是真的。 my_instance将是无法使用的无效实例。

http://www.gotw.ca/publications/mill13.htm

答案 1 :(得分:2)

您可以使用1995年C ++标准中引入的鲜为人知的功能 - function-try-block,如下所示:

struct A
{
private:
  char* data;
public:
  // catch exception in the constructor
  A() try : data( new char [10000000000] ) {}
  catch ( std::bad_alloc ) { data = NULL; /* handle bad_alloc exception here */ }

  void write (int x) {
    if ( data ) data[x] = 1;
  }
};

如果A从某个基类继承,则此方法不可用。而且你可以捕获bad_alloc异常的事实最终没有给你任何东西。如果您可以使用较少的已分配内存,则可以使用std::get_temporary_buffer代替new

struct A
{
private:
  std::pair<char*,ptrdiff_t> data;
public:
  // get as much memory as possible
  A() : data( std::get_temporary_buffer<char>(10000000000) ) {}
  ~A() { std::return_temporary_buffer( data.first ); }

  void write (int x) {
    if ( x < data.second ) // check x is in the allocated range
      data.first[x] = 1;
  }
};

答案 2 :(得分:0)

如何使用非投掷分配器......

my_class(void)
   : data(new (std::nothrow) char[1000000])
{
}

bool isvalid(void) const { return data != 0; }

虽然 function-try-block 是记录失败的好方法,但它无法挽救对象(来自草案3225,第[except.handle]部分):

  

在进入处理程序之前,应完全构造基类和对象成员   该对象的构造函数的function-try-block。

     

如果控制到达function-try-block的处理程序的末尾,则重新抛出当前处理的异常   构造函数或析构函数。

答案 3 :(得分:0)

是的 - 它被称为在尝试中写它。

int main() {
    try {
        my_class my_instance;
        my_instance.write(10);
        std::cout << "OK.\n";
        return 0;
    }
    catch (std::bad_alloc&) {
        std::cout << "Memory overflow.\n";
        return 1;
    }
}

答案 4 :(得分:0)

我不确定抛出异常的构造函数有什么问题,我当然不会使用init()方法。请参阅The C++ Programming Language,其中有一个注释,其中有四个主要原因,不使用它。

我通常会编写这样的main()函数,以避免核心转储并写入应用程序的调试日志,以确保有一些确切的信息发生。

int main ( int argc, char ** argv )
try
{
    // do some stuff
    //...
    return EXIT_SUCCESS;
}
    // lots of stuff, including `std::bad_alloc`.
catch ( const std::exception& )
{
    // write to application debug log.
    // ...
    return EXIT_FAILURE;
}
    // any unkonwn exception, possibly from 3rd-party library.
catch ( ... ) 
{
    // write to application debug log.
    // ...
    return EXIT_FAILURE;
}