问题描述
我要在此结构中添加move构造函数和move赋值运算符。 有人可以告诉我他们写得好吗? 当我在没有这两种方法的情况下运行代码时,一切正常,但是,当我添加这两种方法时,则无法正常工作。 非常感谢
struct Data {
Data() = default;
Data(const unsigned int _x) : data(new unsigned char[_x]),size(_x) {}
Data(const Data &_d) : data(new unsigned char[_d.size]),size(_d.size) {
memcpy(data,_d.data,_d.size);
}
~Data() {
delete[] data;
size = 0;
};
Data& operator=(const Data &_d) {
if (this == &_d) {
return *this;
}
unsigned char *tmp(new unsigned char[_d.size]);
memcpy(tmp,_d.size);
delete[] data;
data = tmp;
size = _d.size;
return *this;
}
这是我的move构造函数,应该先删除数据,如果大小不相等,再分配新大小的数据吗?
Data(Data &&_d)
{
data = _d.data;
_d.data = nullptr;
size = _d.size;
_d.size = 0;
}
这是我的移动分配运算符
Data& operator=(Data&& _d)
{
if (this != &_d)
{
delete[] data;
data = _d.data;
_d.data = nullptr;
size = _d.size;
_d.size = 0;
}
return *this;
}
unsigned char *data = nullptr;
unsigned int size = 0;
};
解决方法
您已经在课堂上提供了begin和end方法。可能您想使用STL。在这种情况下,如果要提供强大的异常保证,则应添加noexcept。如果STL容器为noexcept(false),则它们不会使用您的move构造函数/分配。
Data& operator=(Data&& _d) noexcept
{
if (this != &_d)
{
delete[] data;
data = _d.data;
_d.data = nullptr;
size = _d.size;
_d.size = 0;
}
return *this;
}
Data(Data &&_d) noexcept
{
data = _d.data;
_d.data = nullptr;
size = _d.size;
_d.size = 0;
}
,STL容器在调整大小时只能使用move构造函数 如果该构造函数没有破坏其强异常的操作 安全保证。用更简单的语言,它不会使用移动 对象的构造函数(如果可以抛出异常)。这是 因为如果在移动过程中引发了异常,则 被处理的内容可能会丢失,就像在复制构造函数中那样 原始不会改变。
您的验证码是正确的。
但是还有一种使用https://youtu.be/KVOiKz-ddwk来实现移动分配的模式:
Data& operator=(Data&& _d)
{
std::swap(data,_d.data);
std::swap(s,_d.size);
return *this;
}
在此,调用_d
析构函数时将释放旧数据。
这不是“更正确的方法”,但是更容易编写,并且留下更少的空间来忘记正确配置资源。
移动构造函数可以重用移动分配:
Data(Data&& _d)
: this()
{
*this = std::move(_d);
}
同样,这不是更好的方法,但是可以减少重复代码的数量。