我正在研究具有多个动态字段的类,并且我正在寻找编码赋值运算符的快速方法。
因此,我有一些基本类Cla
,它存储整数的动态数组(arr
)和该数组的大小(n
)。
我已经对此进行了编码:
Cla::Cla(int* arr, int n) : n(n)
{
this->arr = new int[n];
//allocation error handling
while (--n >= 0)
this->arr[n] = arr[n];
}
Cla::~Cla()
{
delete[] arr;
}
Cla::Cla(const Cla& copy) : Cla(copy.arr, copy.n){}
Cla& Cla::operator= (const Cla& asg)
{
this->~Cla();
*this = asg;
return *this;
}
[operator=
除外,所有正常工作。我的想法是,我将销毁我的对象,然后使用复制构造函数再次创建它(为简化示例,我不考虑两个对象具有相同大小且无需释放和新分配)。它可以编译,但是执行时却给了我一些讨厌的错误。
您能给我一些有关如何更正此代码的建议吗?这样工作是否有可能?(我知道如何编写一个赋值运算符,我只是问是否可以使用析构函数和复制构造函数来实现。我在互联网上找不到类似的东西。)
您的operator=
具有未定义的行为。首先,您不能在未使用placement-new
分配的对象上手动调用析构函数。其次,一旦对象被销毁,将无法再使用它,这意味着一旦placement-new
被调用,*this = asg
将访问无效内存,因为this->~Cla()
不再指向有效对象。第三,您的this
正在运行一个无限递归循环,一遍又一遍地调用自己,直到调用堆栈崩溃为止(如果幸运的话)。
由于要使用副本构造函数,因此最好使用operator=
来更好地服务operator=
。构造一个本地对象以使用您的副本构造函数,然后用copy-swap idiom交换该对象的内容,例如:
this
或者:
Cla& Cla::operator= (const Cla& asg)
{
if (&asg != this)
{
Cla temp(asg);
std::swap(arr, temp.arr);
std::swap(n, temp.n);
}
return *this;
}
话虽如此,您的复制构造函数是delegating到转换构造函数的事实,这意味着您使用的是C ++ 11或更高版本,在这种情况下,您还应该在类中实现移动语义,而不仅仅是复制语义,例如:
void Cla::swap(Cla &other)
{
std::swap(arr, other.arr);
std::swap(n, other.n);
}
Cla& Cla::operator= (const Cla& asg)
{
if (&asg != this) {
Cla(asg).swap(*this);
}
return *this;
}
通过按值传递Cla::Cla() : arr(nullptr), n(0)
{
}
Cla::Cla(int* arr, int n) : arr(new int[n]), n(n)
{
while (--n >= 0)
this->arr[n] = arr[n];
}
Cla::Cla(Cla &&c) : arr(nullptr), n(0)
{
c.swap(*this);
}
Cla::Cla(const Cla& c) : Cla(c.arr, c.n)
{
}
Cla::~Cla()
{
delete[] arr;
}
void Cla::swap(Cla &other)
{
std::swap(arr, other.arr);
std::swap(n, other.n);
}
Cla& Cla::operator= (Cla asg)
{
asg.swap(*this);
return *this;
}
参数,这允许asg
基于是否将左值或右值传递给它来决定使用复制语义还是移动语义。构造operator=
参数时,编译器将选择适当的构造函数。