我想将我的复制操作符重定向到我的复制构造函数。在后者的位置,我实现了基于旧的avaialble类复制/构造新类的正确逻辑。
然而,如何正确地做到这一点?我“想”这个可能会泄漏内存,但我不知道怎么做而不通过指针:
MyClass& MyClass::operator=(const MyClass& a) {
MyClass* b = new MyClass(a);
return *b;
}
这样好吗?如果不是,那么正确的方法是什么?我应该更改方法的主体还是原型?
谢谢。
答案 0 :(得分:2)
不,operator=
应将当前对象属性设置为与分配的对象相同。您的方法在堆上分配一个新对象,将其作为引用返回(基本上将其泄漏),并使调用操作符的对象完全保持不变。
您应该实现一个名为CopyFrom()
的方法,该方法分配所有对象的属性以匹配传入对象的属性(深度复制任何堆分配的指针,其生命周期由MyClass
管理)然后从您的复制构造函数和您的operator=
调用THAT。
class MyClass
{
public:
MyClass( const MyClass& in )
{
CopyFrom( in );
}
MyClass& operator=( const MyClass& in )
{
CopyFrom( in );
return *this;
}
private:
void CopyFrom( const MyClass& in )
{
... copies in's attributes into self.
}
};
答案 1 :(得分:1)
除非您在MyClass中存储指针,否则正确的复制赋值运算符是默认生成的运算符。但是,如果你需要实现一个,你可以通过copy-swap惯用语来复制构造函数:
MyClass& MyClass::operator = (MyClass const& a) {
MyClass temp(a); // Call the copy constructor
using std::swap;
swap(temp, *this);
return *this;
}
using std::swap
的原因是启用依赖于参数的查找。如果为MyClass定义自己的交换函数,则会调用它。否则std::swap
将用作后备。 (编辑:在这种情况下,你确实需要实现自定义交换,否则你将获得无限递归。std::swap
将使用赋值运算符,它将调用std::swap
,它将调用。 ..)
这个成语很受欢迎的原因是因为std::swap
是一个无投掷功能。如果你的拷贝构造函数抛出异常,那么你分配的对象仍处于有效状态。
答案 2 :(得分:1)
通常,复制赋值运算符永远不应创建副本。相反,它应该将数据复制到它所调用的现有对象(赋值的左侧)。例如:
class MyClass
{
public:
MyClass & operator = (const MyClass & RHS)
{
// Copy data from RHS into 'this'
m_value = RHS.m_value;
return *this;
}
private:
int m_value;
};
在这种情况下,不需要定义自己的复制构造函数,因为默认(编译器提供的)工作正常。这只是一个例子。
不幸的是,您无法在现有对象上调用复制构造函数。复制交换模式是一种替代方案,但效率可能较低。
答案 3 :(得分:0)
“正确的方法”是像赋值运算符一样实现赋值运算符:修改调用运算符的对象的内容并返回对它的引用。
您当前的实现将导致内存泄漏,并且不执行任何赋值(这是赋值运算符的主要点)。
如果你只想编写一次赋值代码,并且你的类没有在构造函数中分配内存,你可以这样做:
MyClass::MyClass(const MyClass& a) {
*this = a;
}
MyClass& MyClass::operator=(const MyClass& a) {
if (&a == this)
return *this;
// Do assignment
return *this;
}
但我不推荐它。
答案 4 :(得分:0)
您的代码完全错误(抱歉)!赋值运算符 不分配任何东西,但分配一个指向MyClass对象的指针, 造成内存泄漏。我的建议:避免指针或使用一些 智能指针(shared_ptr,unique_ptr),但这只是一个旁注。
也许这很有帮助:
#include <iostream>
#include <limits>
class X
{
public:
X(std::size_t n)
: m_size(n), m_data(new int[n])
{
std::cout << "Construct" << std::endl;
}
~X()
{
std::cout << "Destruct" << std::endl;
delete [] m_data;
}
// Exception safe assignment.
// Note: I am passing by value to enable copy elision and
// move semantics.
X& operator = (X x) {
std::cout << "Assign" << std::endl;
x.swap(*this);
return *this;
}
void swap(X& x) {
std::swap(m_size, x.m_size);
std::swap(m_data, x.m_data);
}
std::size_t size() const { return m_size; }
private:
std::size_t m_size;
int* m_data;
};
int main()
{
X x(1);
try {
x = X(2);
// To provoke an exception:
std::size_t n = std::numeric_limits<std::size_t>::max();
x = X(n);
}
catch(...) {
std::cout << "Exception" << std::endl;
}
std::cout << "Size: " << x.size() << std::endl;
return 0;
}
答案 5 :(得分:-1)
如果您绝对想要通过复制构造函数实现赋值运算符,请使用以下命令:
MyClass& MyClass::operator=(const MyClass& o)
{
this->~MyClass(); // destroy current object
new(this) MyClass(o); // use the copy constructor
return *this;
}
我无法想到这是最好的事情(其他答案描述了在某些情况下更好的实施方式)。
如果MyClass
包含数百个int / float字段,并且有几个动态分配的指针,那么可能(只是试图在这里做一些事情)?
NULL
然而,不鼓励在你的班级中使用裸(非智能)指针。如果你有这样一个类,那么你有比非工作赋值运算符更糟糕的问题 - 你必须先重构,问题就会消失,再加上所有其他错误。