向量重新分配使用复制而不是移动构造函数

bja*_*fly 12 c++ gcc move-semantics c++11

嗨我使用gcc 4.7创建了一个带有noexcept移动构造函数的类Foo,并将向量保留大小设置为2,这样在添加第3项时就必须重新分配大小.在执行此操作时,它似乎正在调用复制构造函数而不是移动构造函数.我在这里错过了什么吗?

#include <vector>
#include <iostream>

class Foo
{
  public:
  Foo(int x) : data_(x)
  {
    std::cout << " constructing " << std::endl;
  }

  ~Foo()
  {
    std::cout << " destructing " << std::endl;
  }

  Foo& operator=(const Foo&) = default;
  Foo& operator=(Foo&&) = default;

   Foo(Foo&& other) noexcept : data_(std::move(other.data_))
   {
    std::cout << " Move constructing " << std::endl;
   }

   Foo(const Foo& other) noexcept :  data_(other.data_)
   {
    std::cout << " Copy constructing " << std::endl;
   }

  private:
  int data_;
};


int main ( int argc, char *argv[])
{
  std::vector<Foo> v;
  v.reserve(2);
  v.emplace_back(1);
  std::cout << "Added 1" << std::endl;
  v.emplace_back(2);
  std::cout << "Added 2" << std::endl;
  v.emplace_back(3);
  std::cout << "Added 3" << std::endl;
  std::cout << "v size: " << v.size() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

输出:

 constructing 
Added 1
 constructing 
Added 2
 constructing 
 Copy constructing 
 Copy constructing 
 destructing 
 destructing 
Added 3
v size: 3
 destructing 
 destructing 
 destructing 
Run Code Online (Sandbox Code Playgroud)

sya*_*yam 13

在使用GCC 4.7和4.8进行修改之后,它似乎确实是4.7中的一个错误,只有当类的析构函数标记时才出现noexcept:

struct Foo {
  Foo() {}
  ~Foo() noexcept {}
  Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
  Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};

int main() {
  std::vector<Foo> v;
  v.reserve(2);
  v.emplace_back();
  v.emplace_back();
  v.emplace_back();
}
Run Code Online (Sandbox Code Playgroud)

GCC 4.7显示:

move constructor
move constructor
Run Code Online (Sandbox Code Playgroud)

如果我们noexcept从析构函数中删除:

struct Foo {
  Foo() {}
  ~Foo() {}
  Foo(Foo&&) noexcept { std::cout << "move constructor" << std::endl; }
  Foo(const Foo&) noexcept { std::cout << "copy constructor" << std::endl; }
};
Run Code Online (Sandbox Code Playgroud)

GCC 4.7显示:

copy constructor
copy constructor
Run Code Online (Sandbox Code Playgroud)

GCC 4.8在两种情况下都使用移动构造函数.

  • +1 [发现错误](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56191).`G ++ 4.7不应用析构函数为noexcept的规则,因此需要在析构函数上添加显式的noexcept规范.GCC 4.8正确地使析构函数不受C++ 11`的要求 (9认同)