为什么noexcept移动构造函数在向量重新分配期间没有被调用?

时间:2017-04-29 00:51:04

标签: c++ c++14 noexcept

正如我们所知,当新元素添加到std :: vector(通过push_back)时,它可能缺少空间,对于这些情况,vector会分配更大的内存块来保存其所有元素,然后从现有块转移到在C ++ 98中,这是通过从旧位置复制元素然后销毁这些对象来完成的,因此它可以提供强大的异常保证,在c ++ 11中,它可以使用移动构造函数进行优化,前提是它不是新的但是如果我的析构函数是noexcept(false),那么为什么不进行优化会发生什么呢?

#include <iostream>
#include <vector>

class X
{
public:
    X()
    {
    }
    X(const X& ob) noexcept
    {
      std::cout<<"Copy Constructor...."<<std::endl;
    }
    X(X&& ob) noexcept
    {
       std::cout<<"Move Constructor...."<<std::endl;
    }
    ~X() noexcept(false)
    {
    }
};
int main()
{
   std::vector<X> myobs;
   for(int i=0;i<1000;i++)
   {
      myobs.push_back(X());
   }
   return 0;
}

为什么在上面的场景中调用了复制构造函数,并且还注意到如果我将析构函数设置为noexcept(默认行为),那么只会调用移动构造函数。

为了增加我对强异常保证的理解(在vector :: push_back中),旧内存中的所有元素都不会被销毁,直到所有元素都被成功复制,这意味着在最后调用析构函数,所以它们是否无关紧要是noexcept或不是

1 个答案:

答案 0 :(得分:4)

问题在于is_nothrow_move_constructible<T>的规范,当前指定用于检查表达式

T(declval<T&&>())

是noexcept,但它涉及析构函数(临时的)以及移动构造函数。这可以说是一个图书馆缺陷,是正在进行的LWG 2116的主题。 GCC遵循规范是正确的;规范本身就很糟糕。