Copy constructor chosen over move constructor when returning non-static local object

↘锁芯ラ 提交于 2020-07-29 07:38:48

问题


I used to assume that a class' move constructors would be given priority over its copy constructors, but in the code below it seems that the copy constructor is chosen even though the object should be movable.

Do you have any idea why below codes choose copy constructor when foo() returns vector<B> B?

#include <iostream>
#include <vector>

using namespace std;

class B {
public:
  int var_;

  B(int var) : var_(var)
  {
    cout << "I'm normal" << endl;
  }

  B(const B& other)
  {
    cout << "I'm copy constructor" << endl;
  }

  B(B&& other)
  {
    cout << "I'm move constructor" << endl;
  }
};

vector<B> foo()
{
  vector<B> b;

  b.push_back(1);
  b.push_back(2);

  return b;
}

int main()
{
  vector<B> b {foo()};
}

The result is as shown below.

$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor
I'm normal
I'm move constructor
I'm copy constructor

Curiously, if I remove one line in foo(), the move constructor is chosen instead:

vector<B> foo()
{
  vector<B> b;

  b.push_back(1);

  return b;
}

Now the result is like below:

$ g++ main.cpp
$ a.out
I'm normal
I'm move constructor

回答1:


There are two things involved: vector reallocation and selection of mechanism when reallocating.

First, reallocation occurs here:

vector<B> foo()
{
  vector<B> b;

  b.push_back(1);
  std::cout << "Vector capacity: " << b.capacity() << " Vector size: " << b.size() << "\n";
  b.push_back(2); //capacity() == size(), reallocation is needed

  return b;
}

Most vector implementations make capacity 2*current_capacity when current_capacity would be exceeded, to conform to amortized-constant complexity required by standard.


Now, compiler can only choose move constructor for reallocation if it is marked as noexcept. In order to make vector use move constructor, declare it like this:

B(B&& other) noexcept
{
//
}

You can remove the reallocation altogether by reserving space upfront:

vector<B> foo()
{
  vector<B> b;
  b.reserve(2);
  b.push_back(1);
  b.push_back(2);

  return b;
}

Or by initializing vector in one go:

vector<B> foo()
{
  return vector<B>{1, 2};
}


来源:https://stackoverflow.com/questions/62894254/copy-constructor-chosen-over-move-constructor-when-returning-non-static-local-ob

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!