向量重新分配使用副本而不是移动构造函数 [英] Vector reallocation uses copy instead of move constructor

查看:132
本文介绍了向量重新分配使用副本而不是移动构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您好,我创建了一个带有noexcept的类Foo,使用gcc 4.7移动构造函数,并将矢量保留大小设置为2,以便在添加第三项时它将不得不重新分配大小。看起来这样做是在调用复制构造函数而不是移动构造函数。我在这里错过了什么?

  #include< vector> 
#include< iostream>

class Foo
{
public:
Foo(int x):data_(x)
{
std :: cout< < 构造<<的std :: ENDL;
}

〜Foo()
{
std :: cout<< 破坏<<的std :: ENDL;
}

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

Foo(Foo& other)noexcept:data_(std :: move(other.data_))
{
std :: cout<< 移动构建<<的std :: ENDL;
}

Foo(const Foo& other)noexcept:data_(other.data_)
{
std :: cout<< 复制构建<<的std :: ENDL;
}

private:
int data_;
};


int main(int argc,char * argv [])
{
std :: vector< Foo> v;
v.reserve(2);
v.emplace_back(1);
std :: cout<< 添加了1<<的std :: ENDL;
v.emplace_back(2);
std :: cout<< 添加2<<的std :: ENDL;
v.emplace_back(3);
std :: cout<< 添加3<<的std :: ENDL;
std :: cout<< v size:<< v.size()<<的std :: ENDL;
}

输出:

<$
构建
增加1
构建
增加2
构建
复制构建
复制构造
破坏
破坏
加入3
v size:3
破坏
破坏
破坏


解决方案

经过GCC 4.7和4.8的修改之后,它似乎确实是4.7中的一个bug,仅当类的析构函数 标记为 noexcept 时才会出现:

<$ $ {
Foo(){}
〜Foo()noexcept {}
Foo(Foo&& amp;)noexcept {std :: cout << 移动构造函数<<的std :: ENDL; }
Foo(const Foo&)noexcept {std :: cout<< 复制构造函数<<的std :: ENDL; }
};

int main(){
std :: vector< Foo> v;
v.reserve(2);
v.emplace_back();
v.emplace_back();
v.emplace_back();

$ / code>

GCC 4.7显示:

 移动构造函数
移动构造函数

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

  struct Foo {
)Foo(){}
〜Foo(){}
Foo(Foo&&)& 移动构造函数<<的std :: ENDL; }
Foo(const Foo&)noexcept {std :: cout<< 复制构造函数<<的std :: ENDL; }
};

GCC 4.7显示:

 复制构造函数
复制构造函数

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

Hi I created a class Foo with a noexcept move constructor using gcc 4.7 and set the vector reserve size to 2 so that it would have to reallocate the size when adding the 3rd item. It seems it is calling the copy constructor instead of the move constructor when doing this. Am I missing something here?

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

output:

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

解决方案

After tinkering with it a bit with both GCC 4.7 and 4.8, it seems that it is indeed a bug in 4.7, which only appears when the class' destructor is not marked 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();
}

GCC 4.7 displays:

move constructor
move constructor

If we remove noexcept from the destructor:

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 displays:

copy constructor
copy constructor

GCC 4.8 uses the move constructor in both cases.

这篇关于向量重新分配使用副本而不是移动构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆