为什么需要在c++运算符重载中删除内存并分配新内存



我正在检查赋值运算符的实现,但我不理解这一点:

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
}

为什么我不能这样做,而不释放内存,然后分配新内存?

void operator=(const MyString& rhs)
{ 
if (this != &rhs) {
strcpy(this->str, rhs.str); // copy characters
this->length = rhs.length; // copy length
}
}

为什么我不能更新现有内存中的值?

从中复制的MyString可以是与分配给的MyString不同的length

无法调整数组的大小。要创建不同大小的阵列,必须销毁旧阵列,然后用新阵列替换。这就是第一个代码正在做的事情。

在第二段代码中,只有当新阵列的大小较小或相等时,才有意义重用现有阵列,而您没有检查这一点,例如:

const MyString& operator=(const MyString& rhs)
{ 
if (this != &rhs) {
if (rhs.length > this->length) {
delete[] this->str;
this->str = new char[rhs.length + 1];
}
strcpy(this->str, rhs.str);
this->length = rhs.length;
}
return *this;
}

在这种情况下,您应该考虑添加另一个成员capacity,以更好地区分为阵列物理分配的char数量与阵列内部逻辑有效的char数量,例如:

MyString()
: str(NULL), length(0), capacity(0)
{
}
MyString(const MyString& src)
: str(NULL), length(0), capacity(0)
{
if (src.str) {
this->capacity = rhs.length; // optionally round up to an even boundary of your choosing
this->str = new char[this->capacity + 1];
strcpy(this->str, src.str);
this->length = rhs.length;
}
}
const MyString& operator=(const MyString& rhs)
{ 
if (this != &rhs) {
if (rhs.length > this->capacity) {
delete[] this->str;
this->capacity = rhs.length;  // optionally round up to an even boundary of your choosing
this->str = new char[this->capacity + 1];
}
strcpy(this->str, rhs.str);
this->length = rhs.length;
}
return *this;
}

为什么Just I不能更新现有内存中的值

如果LHS有足够的内存,就可以这样做。否则,您将不得不取消分配旧内存并分配新内存。

const MyString& operator=(const MyString& rhs)
{ 
if (this != &rhs) {
if ( this->length < rhs.length )
{
this->length = rhs.length;
delete[] this->str;
this->str = new char[strlen(this->length) + 1];
}
strcpy(this->str, rhs.str);
}
return *this;
}

首先,operator =应该返回对指定对象的引用。也就是说,它应该像一样声明

MyString & operator=(const MyString& rhs);

存储在类MyString的指定对象中的字符串可以短于存储在指定对象中。在这种情况下,此语句

strcpy(this->str, rhs.str);

可能导致内存覆盖超出调用未定义bejavior的已分配字符串。

请注意,不需要调用标准函数strlen,因为数据成员长度已经存储了字符串的长度。运算符可以通过以下方式定义。

const MyString& operator=(const MyString& rhs)
{ 
if ( this != &rhs ) 
{
if ( this->length != rhs.length )
{
delete[] this->str; // Why is this required?
this->str = new char[rhs.length + 1];
this->length = rhs.length;
}
strcpy( this->str, rhs.str );
}
return *this;
}

只有当rhs字符串比您已经分配的空间长时,才需要分配新内存:

MyString& operator=(const MyString& rhs) {  // don't return a `const&`
if (this != &rhs) {
if(length < rhs.length) {
delete[] str;
str = new char[rhs.length + 1];
}
length = rhs.length;
std::memcpy(str, rhs.str, length + 1);
}
return *this;
}

请注意,如果不添加capacity成员变量,这将丢失有关额外空间的信息。加上这个,它看起来是这样的:

MyString& operator=(const MyString& rhs) { 
if (this != &rhs) {
if(capacity < rhs.length) {
delete[] str;
capacity = rhs.length;
str = new char[capacity + 1];
}
length = rhs.length;
std::memcpy(str, rhs.str, length + 1);
}
return *this;
}

演示

最新更新