提问者:小点点

为什么当我返回非静态本地对象时,复制构造函数优先于移动构造函数?


我曾经假设移动构造函数优先于复制构造函数
,但是在下面的测试中,我发现选择了复制构造函数

您是否知道当foo()返回向量时,下面代码为什么选择复制构造函数; 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()};
}

结果如下

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

甚至我在foo中删除了一行,它选择了移动构造函数。。。。

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

  b.push_back(1);

  return b;
}

现在结果如下所示

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

共1个答案

匿名用户

其中涉及到两件事:向量重新分配和重新分配时机制的选择。

首先,这里发生重新分配:

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

大多数向量实现在超过current_capacity时使容量2*current_capacity,以符合标准要求的摊销恒定复杂度。

现在,编译器只能选择移动构造函数进行重新分配,如果它被标记为noexcept。 为了使vector使用move构造函数,像这样声明它:

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

您可以通过预先保留空间来完全删除重新分配:

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

  return b;
}

或者通过一次性初始化vector:

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