如果在分配期间抛出异常会发生什么?

时间:2015-07-07 17:40:10

标签: c++ exception

我有以下功能模板:

template<typename T>
void init(std::vector<T>& v, int min, int max)
{
    for(int i = min; i <= max; i++)
        v.push_back(new T());
}

将使用另一个函数,如下所示:

void foo()
{
    std::vector v;
    init(v, 10, 20);
    //something else
}

如果在函数T中初始化init类型的某个对象期间抛出某些异常会发生什么?

在这种情况下或某些其他类型的UB,我会得到内存泄漏吗?如果是这样,我该如何预防?

4 个答案:

答案 0 :(得分:4)

如果内存分配失败,您将获得std::bad_alloc异常。如果在执行类型T的构造期间存在异常,则应使用try catch块在类型T的构造函数中处理。

如果使用std::vector::push_back运算符创建对象后new失败,则存在内存泄漏的可能性,因为新生成的原始指针还不是向量的一部分。因为您正在创建一个原始向量使用new运算符生成的指针,作为正确清理的一部分,您应该对向量的内容调用deletestd::vector<>析构函数只清除指针,但不清除T类型的对象。

要解决此原始指针问题,如果您有C ++ 11编译器,则可以依赖std::shared_ptrstd::unique_ptr代替原始指针

答案 1 :(得分:4)

  

在这种情况下或其他类型的UB中我是否会出现内存泄漏?

假设T表现良好 * ,则不会出现内存泄漏,并且行为已完全定义。

C ++标准保证它将运行std::vector<T>的析构函数,清理已分配给该向量的内存。此外,C ++标准保证如果push_back()抛出异常,该函数没有效果,这意味着你的向量仍然可以安全地销毁。

* 表现良好我的意思是T应该释放与之相关的资源。 表现良好的T的一个常见示例是一个简单的指针:它不会用于清理。

答案 2 :(得分:1)

表达式new T()通常会做两件事:

  1. 为T
  2. 分配内存
  3. 在该内存中构建T
  4. 如果构造函数抛出异常(并且堆栈中的某些内容正在处理异常),则在异常向上传播到堆栈之前,将释放在步骤1中分配的内存。这里没有内存泄漏。

    回答上一级发生的事情需要澄清问题中的代码,因为矢量的类型与其使用不匹配。

答案 3 :(得分:0)

如果抛出异常,它会恢复您的函数调用,直到它到达try catch块。

如果此调用与您的main之间没有尝试捕获,则程序将以错误值退出。

您可以像这样管理它:

std::vector v;

try
  {
    init(v, 10, 20);
    // Init was successful, continue execution here
  }
catch (const std::exception& exception)
  {
    // An exception was thrown in init or after
    std::cerr << exception.what() << std::endl; // Print exception error message
  }

无论如何,如果你在try-catch块之前声明它,你的矢量不会受到任何内存泄漏的影响。