使用内存移动构造函数
Move constructor with memcpy
>我有一个结构,我想它是不可复制的,只能移动的,但由于它包含很多 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 myStruct &)=delete;
myStruct(myStruct && other);
};
这种移动构造函数会有什么问题:
myStruct::myStruct(myStruct && other){
std::memcpy(this,&other,sizeof(myStruct));
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);
}
注意 std::complex
是一种文本类型,放入 pod 成员中应该是安全的。如果添加任何其他类类型的成员对象,则必须验证自己是否对memcpy安全。
正如 Jonathan Wakely 指出的那样,更好的实现将回避对 pod 和非 pod(或文字和简单初始化)成员的担忧。相反,按是否要复制或移动成员对成员进行分组:
struct myStruct{
struct {
int a,b,c,d;
double e,f,g,h;
std::complex<double> value1,value2;
} val;
std::unique_ptr<Calculator> calc;
myStruct(){}
myStruct(const myStruct &)=delete;
myStruct(myStruct && other);
};
myStruct::myStruct(myStruct && other)
: val(other.val) // copy the value types
, calc(std::move(other.calc)) // and move the reference types
{
calc->rebind(this);
}
您可以使用默认的移动 Ctor:
myStruct(myStruct&& other) = default;
编辑:在最近的编辑之后,我更喜欢@Useless接受的答案。下面演示一种替代方法,该方法允许将移动构造函数定义为默认值,但与接受的答案相比,该方法被过度设计。
使用memcpy
是一个坏主意。我可能会考虑创建一个执行非三重工作(移动unique_ptr
并重新绑定计算器)的帮助程序类型,并在 myStruct
中使用它,以便可以默认其移动操作:
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);
}
这将允许编译器为 POD 成员生成最佳代码,并且仍然为 unique_ptr<Calculator>
成员执行正确的操作。无需memcpy
。 如果您向myStruct
添加更多成员,移动操作仍将执行正确的操作。
相关文章:
- 为什么不调用移动构造函数?(默认情况下只有构造器,没有别的)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- 为什么调用复制构造函数而不是移动构造函数?
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- 从具有按值捕获的 lambda 移动构造 std::函数时,移动构造函数调用两次
- 具有已删除移动和复制构造函数的类的就地构造
- 移动构造函数和右值引用
- 使用移动调用对等构造函数unique_ptr默认构造函数
- 为什么 std::memmove 中联合的默认非平凡移动构造函数C++?
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- 构造函数采用std::string_view与std::string并移动
- C++:为什么不调用移动构造函数?
- 了解构造函数在移动、复制、赋值语义中的行为
- 没有移动的构造函数移动课程
- 引用绑定和复制构造函数/移动构造函数
- 构造函数移动
- C++ 向量实现 - 移动构造函数 - 移动与前进
- 我真的必须取消移动构造函数/移动结构中的所有成员还是只是指针
- 将类(没有默认构造函数)移动到另一个类的move构造函数中