std::vector<>::emplace_back() 中的异常安全?

Exception in std::vector<>::emplace_back() safe?

本文关键字:安全 异常 lt vector gt emplace std back      更新时间:2023-10-16

std::vector<>::emplace_back()抛出异常时会发生什么?

例如:

class Foo {
public:
  Foo(int bar) {
    if (bar == 4) throw std::exception("Something went wrong");
  }
}

std::vector<std::unique_ptr<Foo>> foo_list;
foo_list.emplace_back(new Foo(3));
try {
  foo_list.emplace_back(new Foo(4));
} catch (std::exception error) {
  // How bad is it?
}
// Whats inside foo_list now?

我希望向量只包含第一个Foo对象。

是这样吗?这是标准所保证的吗?

还有:可能有任何内存泄漏吗?

我希望向量只包含第一个Foo对象。

是这样吗?这是标准所保证的吗?

是的。上面的注释已经解释了emplace_back甚至从未被调用,因为Foo构造函数在初始化函数参数时抛出。

但是…

还有:可能有任何内存泄漏吗?

是的,你正在使用我在emplace_back(new X)插入智能指针容器中描述的反模式(也发表在Overload Journal #134 - 2016年8月)。

emplace_back需要重新分配向量并且由于内存耗尽而失败时,就会发生问题。传递给函数的指针将丢失,因此会泄漏Foo对象。这可能发生在第一次插入(Foo构造函数不会抛出):

foo_list.emplace_back(new Foo(3));

永远不要使用emplace_back将原始指针插入到unique_ptr的容器中,而是使用make_unique:

foo_list.emplace_back(std::make_unique<Foo>(3));

或者如果你必须使用c++ 11,那么构造unique_ptr并插入或放置它,而不是一个原始指针:

foo_list.emplace_back(std::unique_ptr<Foo>(new Foo(3)));

这样,对象立即由unique_ptr拥有,因此,如果emplace_back内部发生异常,该对象将被正确销毁。