【问题标题】:Vector reallocation uses copy instead of move constructor向量重新分配使用复制而不是移动构造函数
【发布时间】:2013-09-10 10:11:47
【问题描述】:

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

#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;
}

输出:

 constructing 
Added 1
 constructing 
Added 2
 constructing 
 Copy constructing 
 Copy constructing 
 destructing 
 destructing 
Added 3
v size: 3
 destructing 
 destructing 
 destructing 

【问题讨论】:

  • 我的 clang 构建不会触发一次复制 ctor。获得更智能的 gcc 吗?
  • 它在 GCC 4.8.1 中按预期工作(即vector 调用移动构造函数)。
  • 它适用于gcc 4.8.1。可能是 4.7 中的错误
  • 嗯,有道理我需要升级到 gcc 4.8.1。我永远无法弄清楚它一直困扰着我......那时似乎只是一个错误。非常感谢!

标签: c++ c++11 gcc move-semantics


【解决方案1】:

在对 GCC 4.7 和 4.8 进行了一些修改后,它似乎确实是 4.7 中的一个错误,仅在类的析构函数标记为 @987654322 时才会出现@

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();
}

GCC 4.7 显示:

move constructor
move constructor

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

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

GCC 4.7 显示:

copy constructor
copy constructor

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

【讨论】:

  • +1 Found the bugG++ 4.7 does not apply the rule that destructors are noexcept, so you need to add an explicit noexcept specification on the destructor. GCC 4.8 correctly makes the destructor noexcept as required by C++11.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 2022-11-21
  • 1970-01-01
  • 2017-06-11
  • 2013-10-14
  • 2020-08-13
  • 2015-06-10
相关资源
最近更新 更多