让我们假设我有一个Object MeasurementValues,它有n个不同的指针(这个例子只显示指向原始类型的指针,但也会出现指向其他复杂对象的指针)。
class MesaurementValues {
private:
int *measurement_1;
double *measurement_2;
long long *measurement_3;
//..
float *measurement_n;
int noPointer;
}
我知道,无论如何,这个例子可能有点做作。我尝试在代码中填写Rule of Five。
我必须
this.measurement_x = old.measurement_x ;// for all x = {1,..,n} ?
答案 0 :(得分:1)
首先要注意,移动语义对普通旧数据类型(POD)成员的复制语义没有任何优势,但是当你的类包含其他类对象和/或数组时,它肯定会有用。当你实现move-semantics时,它意味着你有一个"移动构造函数"和/或"移动赋值运算符"在你班上看起来像这样:
class MesaurementValues { private:
int *measurement_1;
double *measurement_2;
long long *measurement_3;
//..
float *measurement_n;
int noPointer;
//a couple different objects
someObject* pObj1;
differentObject* pObj2;
public:
MeasurementValues( MeasurementValues&& move ); //move-constructor
MeasurementValues& operator= (MeasurementValues&& move); //move-assignment
}
- 假设您的类有POD数据和类对象,并且 - 假设有很多变量可以移动:
MeasurementValues::MeasurementValues( MeasurementValues&& old) {
//copy plain-old-data over
measurement_1 = old.measurement_1;
measurement_2 = old.measurement_2;
//copy over values of the pointers
pObj1 = old.pObj1;
pObj2 = old.pObj2;
}
请记住,像其他海报所说的那样,移动语义只有在数据成员是其他可移动对象或动态分配内存时才有优势。
编辑:
指针必须变为"无效",因为它们已被移动。因此,我会将它们设置为null以防止意外行为:
MeasurementValues::MeasurementValues( MeasurementValues&& old)
: measurement_1() //null...
//,...
{
//Swapping null into old...
std::swap(measurement_1, old.measurement_1);
//...
}
答案 1 :(得分:1)
Do I have to
this.measurement_x = old.measurement_x ;// for all x = {1,..,n} ?
我会依赖于pimpl习语,并使用类似于唯一指针的东西。下面是一个详细的例子。请注意,您只需使用Impl,并依赖其默认值(因为它不包含指针)。
#include <iostream>
#include <memory>
struct Moveable
{
public:
Moveable();
~Moveable();
Moveable(const Moveable& m);
Moveable& operator=(const Moveable& m);
Moveable(Moveable&& m);
Moveable& operator=(Moveable&& m);
int foo() const;
private:
struct Impl;
std::unique_ptr<Impl> pimpl_;
};
//Moveable.cpp
struct Moveable::Impl
{
Impl(): a(1), b(2), c(3), buffer(){}
int a, b, c;
char buffer[10000]; //Make it worth our while...
};
int Moveable::foo() const{ return pimpl_->a+pimpl_->b+pimpl_->c;}
Moveable::Moveable()
: pimpl_(new Impl)
{
std::cout << "Default " << (void*)this << std::endl;
}
Moveable::~Moveable()
{
std::cout << "Destruct " << (void*)this << std::endl;
//automagically...
}
Moveable::Moveable(const Moveable&m)
: pimpl_(new Impl(*m.pimpl_))
{
std::cout << "Copying " << &m << " to " << (void*)this << std::endl;
}
Moveable& Moveable::operator=(const Moveable& m)
{
std::cout << "Copy assign " << (void*)&m << " to " << (void*)this << std::endl;
*pimpl_ = *m.pimpl_; //Relying on their defaults...
}
Moveable::Moveable(Moveable&& m)
: pimpl_(move(m.pimpl_))
{
std::cout << "Moving " << (void*)&m << " to " << (void*)this << std::endl;
}
Moveable& Moveable::operator=(Moveable&& m)
{
pimpl_ = move(m.pimpl_);
std::cout << "Move assigning " << &m << " to " << (void*)this << std::endl;
}
int main()
{
Moveable x;
Moveable y(x); //Copying...
y = x; //Copying assign
y = Moveable(); //Default construct, then move assignment, destruct temp
Moveable z(std::move(y));
std::cout << "Calling foo " << z.foo() << std::endl;
return 0;
}