可能std :: vector中的元素有抛出析构函数吗?

时间:2014-11-13 05:34:12

标签: c++ standards-compliance

当我查看有关cppreference的Container要求时,会将Destructible列为value_type的要求。这似乎意味着容器元素的析构函数可能不会抛出。

我还没有能够在C ++ 14标准中找到这个要求的引用(在旧版本中看不到)。我唯一能找到的是value_type必须是Erasable,并不代表任何异常安全。

所以我的问题是,std::vector中的元素可能有抛出析构函数吗?如果没有,标准中的哪个部分禁止它?


P.S。:不用担心,我不打算用抛出析构函数创建类型。我只是编写一个符合标准的实现,并试图获得异常安全权。

2 个答案:

答案 0 :(得分:4)

N4140 [res.on.functions] / 2州:

  

特别是,在以下情况下效果未定义:

     

(2.1) - 对于替换函数(18.6.1),如果安装的替换函数没有实现适用的必需行为的语义:段落。

     

(2.2) - 对于处理函数(18.6.2.3,18.8.3.1,D.11.1),如果安装的处理函数没有实现适用的必需行为的语义:段落

     

(2.3) - 对于在实例化模板组件时用作模板参数的类型,如果对该类型的操作没有实现适用的Requirements子句的语义(17.6.3.5,23.2,24.2,26.2)。除非另有说明,否则此类操作可以通过抛出异常来报告失败。

     

(2.4) - 如果有任何替换函数或处理函数或析构函数退出   例外,除非在适用的必要行为中明确允许:段落。

     

(2.5) - 如果在实例化模板组件时将不完整类型(3.9)用作模板参数,除非特别允许该组件。

这有点模糊,但节省了大量空间,否则会浪费在" T必须满足可破坏的要求"整个图书馆条款的陈述。

值得注意的是,这并不意味着std::vector的元素不具有抛出析构函数;它只意味着当从标准库调用时,所述析构函数必须永远不会抛出。所以例如这个程序符合:

#include <vector>

struct A {
  bool throw_an_int = false;
  ~A() noexcept(false) {
    if (throw_an_int) throw 42;
  }
};

int main() {
  try {
    A a; 
    a.throw_an_int = true;
    std::vector<A> lots_of_As(42);
  } catch(int&) {}
}

答案 1 :(得分:1)

是。标准在一般要求中说明了这一点:

<子> [C++11: §23.2.1/10]:

  

除非另有说明(见23.2.4.1,23.2.5.1,23.3.3.4和   23.3.6.5)本条款中定义的所有容器类型均满足以下附加要求:

     

- 没有erase(),clear(),pop_back()或pop_front()函数抛出异常。

使用clear函数作为示例(由于它不是一般要求的例外),它具有以下要求:

  

销毁a中的所有元素。使引用a元素的所有引用,指针和迭代器无效并且可能使过去的迭代器无效。发布:a.empty()返回true

这意味着它基本上在所有元素上调用std::allocator_traits<Alloc>::destroy。如果t->~T()不可用,则委托给a.destroy(t)。但是,这隐含地保证a.destroy(t)t->~T()都不应该抛出,因为它会违反clearnoexcept规范:

// § 23.3.6.1
void clear() noexcept;

因此,通过演绎,我们可以断言析构函数可以抛出但是必须通过某种机制来抑制它们,例如将它们包装在try-catch块中。

†:经过进一步检查,似乎析构函数可以抛出,但必须按照以下评论中的说明禁止例外。