C++ 使用memcpy移动构造函数
我有一个结构,我想是不可复制的,只能移动的,但因为它包含很多POD,编写移动构造函数会很长,忘记一个变量会很难调试。例如:C++ 使用memcpy移动构造函数,c++,c++11,move-constructor,C++,C++11,Move Constructor,我有一个结构,我想是不可复制的,只能移动的,但因为它包含很多POD,编写移动构造函数会很长,忘记一个变量会很难调试。例如: struct myStruct{ int a,b,c,d; double e,f,g,h; std::complex<double> value1,value2; std::unique_ptr<Calculator> calc; myStruct(){} myStruct(const myStru
struct myStruct{
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
std::unique_ptr<Calculator> calc;
myStruct(){}
myStruct(const myStruct &)=delete;
myStruct(myStruct && other);
};
我可以面对哪些问题?这是否定义明确 您可以使用默认的移动向量:
myStruct(myStruct&& other) = default;
您可以使用默认的移动选择器:
myStruct(myStruct&& other) = default;
最小的更改只是将初始化的成员分组在一起,这样您就可以轻松地
memcpy
它们:
struct myStruct{
struct {
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
} pod;
std::unique_ptr<Calculator> calc;
myStruct(){}
myStruct(const myStruct &)=delete;
myStruct(myStruct && other);
};
myStruct::myStruct(myStruct && other){
std::memcpy(&pod,&other.pod,sizeof(pod));
other.calc.release();
calc->rebind(this);
}
最小的更改只是将初始化的成员分组在一起,这样您就可以轻松地
memcpy
它们:
struct myStruct{
struct {
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
} pod;
std::unique_ptr<Calculator> calc;
myStruct(){}
myStruct(const myStruct &)=delete;
myStruct(myStruct && other);
};
myStruct::myStruct(myStruct && other){
std::memcpy(&pod,&other.pod,sizeof(pod));
other.calc.release();
calc->rebind(this);
}
编辑:在最近的编辑之后,我更喜欢。下面将演示一种替代方法,该方法允许将移动构造函数定义为默认值,但与可接受的答案相比,该方法设计过度。 使用
memcpy
是个坏主意。我可能会考虑创建一个辅助类型来执行非琐碎的工作(移动<代码> UNQUIGYPTR 并重新绑定计算器)并在struct RebindableCalc
{
RebindableCalc();
RebindableCalc(RebindableCalc&& r) noexcept : calc(std::move(r.calc))
{ calc->rebind(self()); }
RebindableCalc& operator=(RebindableCalc&& r) noexcept
{
calc = std::move(r.calc);
calc->rebind(self());
return *this;
}
std::unique_ptr<Calculator> calc;
myStruct* self();
};
struct myStruct : RebindableCalc
{
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
myStruct() = default;
myStruct(myStruct&& other) = default;
myStruct& operator=(myStruct&& other) = default;
};
inline myStruct* RebindableCalc::self()
{
return static_cast<myStruct*>(this);
}
struct RebindableCalc
{
RebindableCalc();
重新绑定计算(重新绑定计算和&r)无例外:计算(标准::移动(r.calc))
{calc->rebind(self());}
RebindableCalc&operator=(RebindableCalc&r)无例外
{
计算=标准::移动(r.calc);
计算->重新绑定(self());
归还*这个;
}
std::唯一计算;
myStruct*self();
};
结构myStruct:RebindableCalc
{
INTA、b、c、d;
双e,f,g,h;
标准::复杂值1,值2;
myStruct()=默认值;
myStruct(myStruct&&other)=默认值;
myStruct&operator=(myStruct&other)=默认值;
};
内联myStruct*RebindableCalc::self()
{
返回静态_cast(此);
}
这将使编译器为POD成员生成最佳代码,并且仍然为
unique_ptr
成员执行正确的操作。不需要memcpy
。如果您向myStruct添加更多成员,移动操作仍然会做正确的事情。编辑:在最近的编辑之后,我更喜欢。下面将演示一种替代方法,该方法允许将移动构造函数定义为默认值,但与可接受的答案相比,该方法设计过度。
使用memcpy
是个坏主意。我可能会考虑创建一个辅助类型来执行非琐碎的工作(移动<代码> UNQUIGYPTR 并重新绑定计算器)并在struct RebindableCalc
{
RebindableCalc();
RebindableCalc(RebindableCalc&& r) noexcept : calc(std::move(r.calc))
{ calc->rebind(self()); }
RebindableCalc& operator=(RebindableCalc&& r) noexcept
{
calc = std::move(r.calc);
calc->rebind(self());
return *this;
}
std::unique_ptr<Calculator> calc;
myStruct* self();
};
struct myStruct : RebindableCalc
{
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
myStruct() = default;
myStruct(myStruct&& other) = default;
myStruct& operator=(myStruct&& other) = default;
};
inline myStruct* RebindableCalc::self()
{
return static_cast<myStruct*>(this);
}
struct RebindableCalc
{
RebindableCalc();
重新绑定计算(重新绑定计算和&r)无例外:计算(标准::移动(r.calc))
{calc->rebind(self());}
RebindableCalc&operator=(RebindableCalc&r)无例外
{
计算=标准::移动(r.calc);
计算->重新绑定(self());
归还*这个;
}
std::唯一计算;
myStruct*self();
};
结构myStruct:RebindableCalc
{
INTA、b、c、d;
双e,f,g,h;
标准::复杂值1,值2;
myStruct()=默认值;
myStruct(myStruct&&other)=默认值;
myStruct&operator=(myStruct&other)=默认值;
};
内联myStruct*RebindableCalc::self()
{
返回静态_cast(此);
}
这将使编译器为POD成员生成最佳代码,并且仍然为
unique_ptr
成员执行正确的操作。不需要memcpy
。如果您向myStruct
添加更多成员,移动操作仍然会做正确的事情。unique\u ptr
肯定会出乱子。它可能必须引用单个内存对象,因此两者都会在同一内存上调用delete,但应使用release()避免
关键是它不能保证,memcpy
ing非POD是UB,不管您可能采取什么预防措施。@UldisK:release
可能(也可能不)使未定义的行为减少灾难性,但是它不会使它有更好的定义。unique\u ptr
肯定会出问题。它可能必须引用单个内存对象,这样两个对象都会在同一内存上调用delete,但是应该使用release()来避免它
关键是它不能保证,memcpy
ing非POD是UB,不管您可能采取什么预防措施。@UldisK:release
可能(也可能不)使未定义的行为减少灾难性,但这不会使它有更好的定义。这不会对他正在做的unique\u ptr
做同样的工作。我的印象是,由于我删除了复制构造函数,所以不应该创建默认的移动构造函数。@BenjaminLindley:的确;它将移动指针,而不是执行某种可能导致指针悬空的未定义行为。@UldisK:如果声明了复制构造函数(已删除或其他),则不会隐式生成移动构造函数。它仍然可以显式生成,如下图所示。@BenjaminLindley:你说得对,我没有发现后面的指针。这让事情变得更糟糕。这不会像他那样对unique\u ptr
做同样的工作。我的印象是,由于我删除了复制构造函数,所以不应该创建默认的移动构造函数。@BenjaminLindley:的确;它将移动指针,而不是执行某种可能导致指针悬空的未定义行为。@UldisK:如果声明了复制构造函数(已删除或其他),则不会隐式生成移动构造函数。它仍然可以显式生成,如下图所示。@BenjaminLindley:你说得对,我没有发现后面的指针。这让事情变得更加糟糕。memcpy(&pod,&other.pod,sizeof(pod))的优点是什么代码>超过pod=other.pod代码>?(答:没有一个)您可能还需要calc=std::move(other.calc)代码>而不是其他.calc.release()代码>否则对象将泄漏并计算->重新绑定(此);