为什么我们需要删除声明?
const MyString& operator=(const MyString& rhs)
{
if (this != &rhs) {
delete[] this->str; // Why is this required?
this->str = new char[strlen(rhs.str) + 1]; // allocate new memory
strcpy(this->str, rhs.str); // copy characters
this->length = rhs.length; // copy length
}
return *this; // return self-reference so cascaded assignment works
}
答案 0 :(得分:10)
这不是复制构造函数,它是赋值运算符。您需要删除,因为正在分配的对象已经保留了以前的值。
此代码也不是很好,因为首先删除旧值然后分配新值...但是分配可能会抛出异常,在这种情况下,对象将保留指向解除分配区域的指针。更好的方法是首先分配然后删除旧值(永远不允许异常从析构函数中逃脱... see this link for an explanation),这样分配成功或失败而不会损害任何内容。
常见的习惯用法是实现复制构造函数和交换操作(交换两个实例的内容,保证不会抛出异常)。然后实现assignment operator combining the two ...这需要更少的代码,并且从异常处理的角度来看是健壮的。
答案 1 :(得分:5)
答案是你必须释放内存,因为如果没有,那么它就会丢失,因为你正在重新使用指针进行新的分配。无论如何,如果你正在学习运算符,那么在复制结构和无投掷交换方面写operator=
是很常见的:
class MyString {
char* str;
int len;
public:
MyString( const MyString& rhs ) : str( new char[ rhs.len ] ), len( rhs.len ) {
memcpy( str, rhs.str, len );
}
~MyString() {
delete str;
}
friend void swap( MyString & lhs, MyString & rhs ) throw() {
using std::swap;
swap( lhs.str, rhs.str );
swap( lhs.len, rhs.len );
}
MyString& operator=( MyString rhs ) { //note: by value
swap( *this, rhs );
return *this;
}
};
请注意,执行的操作类似。现在差异:
整体代码较少。复制时需要执行的任何操作只能在复制构造函数中实现,赋值运算符借用该代码。
无需检查自我分配,因为在旧内存发布之前执行了复制
此实现是异常安全的:如果在分配内存(或复制构造函数中的任何其他操作)时出现问题,则操作没有副作用
自我分配的性能较差,因为新内存已分配,然后被复制和释放。但是临时(rvalue表达式)的赋值会更快,因为编译器可以忽略副本。只有当测量指向代码中的瓶颈时才应考虑性能。
答案 2 :(得分:3)
那不是复制构造函数。那只是一个复制操作员。所以这个> str将指向先前分配的内存。如果在此之前没有释放该内存 - > str被赋予一个新值,那么它将永远不会被释放,因为它的唯一引用已被覆盖。因此,如果没有delete语句,该方法将泄漏内存。
答案 3 :(得分:0)
如果没有delete[]
语句,您将分配内存而不再释放它。如果程序运行的时间足够长,最终会耗尽内存。
new char[]
调用分配新内存并生成指向已分配内存的指针。您将此内存存储在this->str
中 - 覆盖存储在this->str
中的先前指针。
答案 4 :(得分:0)
请参阅Scott Meyers,Effective C ++,2nd Ed。,第11至17项,以全面了解该主题。