当前位置: 首页 > 知识库问答 >
问题:

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

乐宜民
2023-03-14

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

您是否知道当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个答案

白淇
2023-03-14

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

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

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};
}
 类似资料:
  • 在上面的代码中,执行以下语句时不调用复制构造函数: 既然返回是按值的,为什么不调用复制构造函数? 谢啦

  • 问题内容: 如果我在构造函数中返回一些值或对象,那么var会得到什么? 在两种情况下都会得到什么n? 其实这是一个测验问题,答案是什么? 自定义对象构造函数返回什么? a)新实例化的对象 b)未定义-构造函数不返回值 c)不论return语句是 d)等于return语句是什么;新实例化的对象(如果没有return语句) 问题答案: 我发现了这个很棒的链接: 上面提到的第二点魔术是构造函数返回特定的

  • 问题内容: 我知道Go没有任何构造函数,而是在其中使用a ,但是根据此示例。 他们总是回来。为什么仅仅返回就还不够? 更新资料 我尝试过为简单的结构返回创建的对象,这很好。因此,我想知道返回地址是否是构造函数的标准方法或其他方法。 谢谢。 问题答案: 如前所述,是的,规范允许您返回值(作为非指针)或指针。这只是您必须做出的决定。 什么时候返回指针? 通常,如果您返回的值作为指针“更有用”。什么时候

  • 本文向大家介绍C#静态构造函数?相关面试题,主要包含被问及C#静态构造函数?时的应答技巧和注意事项,需要的朋友参考一下 最先被执行的构造函数,且在一个类里只允许有一个无参的静态构造函数 执行顺序:静态变量>静态构造函数>实例变量>实例构造函数  

  • 主要内容:默认拷贝构造函数拷贝和复制是一个意思,对应的英文单词都是 。 对于计算机来说,拷贝是指用一份原有的、已经存在的数据创建出一份新的数据,最终的结果是多了一份相同的数据。例如,将 Word 文档拷贝到U盘去复印店打印,将 D 盘的图片拷贝到桌面以方便浏览,将重要的文件上传到百度网盘以防止丢失等,都是「创建一份新数据」的意思。 在 C++ 中,拷贝并没有脱离它本来的含义,只是将这个含义进行了“特化”,是指用已经存在的对

  • 请考虑以下程序: 如果我运行该程序,我会得到(GoBolt): ...这符合我的预期。但是,如果在线上我将析构函数标记为可能抛出,那么我得到: ...即使用复制因子代替移动因子。为什么会这样呢?复制似乎不能防止移动所必须的破坏。 相关问题: < li >是否要求std::vector使用移动而不是复制? < li >当向量增长时,如何实施移动语义? < li >向量重新分配使用复制而不是移动构造函

  • 我试图理解“有效现代C”中关于特殊成员函数生成的第17项,所以我尝试了一些示例,并试图对一些行为进行推理。书中说: ..当我提到移动操作move构造或移动分配一个数据成员或基类时,不能保证实际会发生移动。“Memberwise移动”实际上更像Memberwise移动请求,因为未启用移动的类型(即,对移动操作不提供特殊支持的类型,例如大多数C 98遗留类)将通过其复制操作“移动”。。。此外,不会为任

  • 问题内容: Java为什么不支持C ++中的复制构造函数? 问题答案: Java。只是没有像在C ++中那样隐式地调用它们,我怀疑这是您的真正问题。 首先,复制构造函数无非是: 现在,C ++将使用以下语句隐式调用复制构造函数: 在这种情况下,克隆/复制在Java中根本没有意义,因为所有b1和b2都是引用,而不是像C 中那样的值对象。在C 中,该语句复制对象的状态。在Java中,它只是复制 引用