【问题标题】:C++11 rvalue reference addressingC++11 右值引用寻址
【发布时间】:2018-07-13 16:42:45
【问题描述】:

我正在尝试理解 c++11 移动语义,并创建了以下沙盒项目:

ma​​in.cpp

#include "my-class.h"
#include <iostream>

MyOtherClass getRValue(void)
{
  MyOtherClass retVal;
  std::cout << "Address of getRValue local var is " << &retVal << std::endl;
  std::cout << "Returning from getRValue...\n";
  return retVal;
}

int main()
{
  MyClass bar(getRValue());
  std::cout << "Address of bar member is " << &(bar.getObjRef()) << std::endl;
  return 0;
}

my-class.h

#ifndef MY_CLASS_H_INCLUDED
#define MY_CLASS_H_INCLUDED

#include <iostream>

class MyOtherClass
{
private:
  int somePOD;
  char someOtherPOD;

public:
  MyOtherClass(void);
  MyOtherClass(MyOtherClass const& argOther);
  MyOtherClass(MyOtherClass&& argOther);
};

class MyClass
{
private:
  MyOtherClass obj;

public:
  MyClass(MyOtherClass&& arg);
  MyOtherClass& getObjRef(void);
};

#endif // MY_CLASS_H_INCLUDED

my-class.cpp

#include "my-class.h"

// Class MyOtherClass
MyOtherClass::MyOtherClass(void)
: somePOD(42), someOtherPOD('x')
{
  std::cout << "MyOtherClass c'tor called.\n";
}
MyOtherClass::MyOtherClass(MyOtherClass const& argOther)
{
  std::cout << "MyOtherClass copy c'tor called.\n";
}
MyOtherClass::MyOtherClass(MyOtherClass&& argOther)
{
  std::cout << "MyOtherClass move c'tor called.\n";
}

// Class MyClass
MyClass::MyClass(MyOtherClass&& arg)
: obj(std::move(arg)) 
{
  std::cout << "MyClass c'tor called.\n";
}
MyOtherClass& MyClass::getObjRef(void)
{
  return this->obj;
}

这段代码打印输出:

MyOtherClass c'tor called.
Address of getRValue local var is 0x7fff882a2db8
Returning from getRValue...
MyOtherClass move c'tor called.
MyClass c'tor called.
Address of bar member is 0x7fff882a2db0

我的问题是:为什么是本地变量的地址。和酒吧会员不同?这两者是否相同不是移动语义的全部意义吗?还是我只是在我的示例中做错了什么?

【问题讨论】:

  • “这不是移动语义的重点吗”?不,不是。移动语义将一个对象的内容移动到另一个对象中。它不会以某种方式神奇地将两个不同的对象合二为一。这些是并且将永远是两个不同的对象。不同的对象总是有不同的地址。在您的示例中,没有真正的 movable 内容,这意味着您示例中的移动语义始终与复制语义相同:所有内容都只是简单地复制。
  • 好吧,是什么让std::vector 成为可移动内容,而int 不是?数据的内容是否应该以某种方式驻留在堆中?只有当我在MyOtherClass 中动态分配数组成员并在移动构造函数中复制指针而不是迭代深拷贝时,这段代码才有意义?
  • 是的,你的想法是对的。事实上,在典型的实现中std::vector 存储了一个指向其元素数组的 指针 - 这就是使 std::vector 可移动的原因。为了将一个向量的内容移动到另一个向量中,您只需要将指针复制到接收者(并重置源)。这就是移动语义真正起作用的地方:您必须将内容间接存储为“指针”或“句柄”。但是当您直接/立即存储内容(如您的示例中)时,移动语义“不起作用”:它被简化为普通的复制语义。
  • @corsel 由 devolpers 显式编码
  • @corsel:这取决于实现细节。如果std::vector 通过原始指针 引用它的数据,那么它必须显式地实现它的移动语义。如果它改用一些智能指针,那么智能指针可能能够自己正确处理它。在任何情况下,它都会归结为原始指针和手动实现。

标签: c++ c++11 move-semantics rvalue-reference


【解决方案1】:

每个对象都有自己的地址。由于barretVal 是不同的对象,因此它们具有不同的地址。移动不会改变对象的地址。

移动的作用是允许您将对象的内脏从一个对象移动到另一个对象。根据课程的制作方式,这可能是一个非常大的性能提升。例如,如果我们有一个像std::vector 这样的类,它将有一个指向它分配的存储的指针。移动允许您将指针和大小从移动的对象复制到移动的对象。然后您只需将已移动对象中的指针设置为空指针并将大小设置为 0。现在我们不必复制任何元素或分配任何存储空间,如果我们要进行复制,我们将不得不这样做.

【讨论】:

  • 所以这只有在我在移动构造函数中实现成员指针复制操作时才有用,对吧?就像当我在MyOtherClass 中有一个大型动态数组时,我不是一个接一个地复制内容,而是简单地复制指针,并防止调用析构函数?
  • @corsel 这就是移动的真正亮点。不过需要注意的是,您不会阻止移动的对象被破坏,您只需将其置于可以破坏的状态,而不会影响您刚刚将胆量移动到的对象。一般来说搬家的成本是小于等于复制成本的。
  • 嗯嗯,比如说,返回的本地对象有一个定义的~MyOtherClass,其中它的成员指针是delete[]d。返回后超出范围,现在怎么办?编译器是否看到超出范围,内容被移动,结束了析构函数调用?
  • @corsel 如果将指针设置为std::nullptr,则deletedelete[] 将变为非操作。
  • @corsel 移动构造函数将移动的对象置于可以安全销毁的状态,并且该销毁不会影响移动的对象。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-10
  • 2013-08-07
  • 2014-12-27
相关资源
最近更新 更多