返回非静态本地对象时,选择复制构造函数而不是移动构造函数 [英] Copy constructor chosen over move constructor when returning non-static local object

查看:59
本文介绍了返回非静态本地对象时,选择复制构造函数而不是移动构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我曾经假设类的移动构造函数的优先级高于其复制构造函数,但在下面的代码中,即使对象应该是可移动的,似乎仍选择了复制构造函数.

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.

您知道为什么 foo()返回 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()};
}

结果如下所示.

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

奇怪的是,如果我在 foo()中删除一行,则会选择move构造函数:

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

现在结果如下:

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

推荐答案

涉及两件事:向量重新分配和重新分配时的机制选择.

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

大多数矢量实现会在超出 current_capacity 时使容量为 2 * current_capacity ,以符合标准要求的分摊不变的复杂性.

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

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

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

这篇关于返回非静态本地对象时,选择复制构造函数而不是移动构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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