C++赋值重载自赋值问题

C++ Assignment overload self-assignment issue

本文关键字:赋值 问题 重载 C++      更新时间:2023-10-16

我目前正在开发一个名为Text的ADT,并且正在重载赋值运算符。当我这样测试运算符时:assignText = alpha,所有输出都正常。然而,当我执行assignText = assignText时,会输出两个实心条。

assignText被声明为Text对象。

我的超负荷分配运算符如下:

void Text::operator= (const Text& other) { 
bufferSize = other.getLength();
buffer = new char[bufferSize];
buffer = other.buffer; 
}

其中int bufferSizechar *buffer

任何提示或建议都将不胜感激。如果还需要什么,请告诉我。

其他答案已经指出了运算符实现中的各种问题。在这里,我将尝试了解发生了什么,即为什么代码的行为与您观察到的一样。如果this == &other,即在自分配期间,则将当前长度作为新缓冲区的大小。这个新缓冲区没有初始化,所以在这一点上它可能包含随机字节。如果是自行分配,则最后一项分配为无操作。综上所述:

void Text::operator= (const Text& other) { 
  bufferSize = other.getLength(); // Take length from current object
  buffer = new char[bufferSize];  // Create new buffer, old buffer turns into a memory leak
  buffer = other.buffer;          // No-op as both are the same variable
}

所以这个告诉你的是,你最终得到了一个当前对象大小的缓冲区,但有未定义的内容。在您的案例中,未定义的内容恰好代表您提到的竖条。

要解决此问题,请确保根据其他答案和注释中的建议修复分配运算符。

这是内存泄漏。您正在为buffer分配两个不同的指针。

 buffer = new char[bufferSize];
 buffer = other.buffer; 

关于手头的问题,C++常见问题解答涵盖了这一点:"我为什么要担心"自分配"?"。首先阅读常见问题解答通常是个好主意。或者至少略读一下。

当您必须实现复制赋值运算符时,通常复制和交换习惯用法就足够了。它也是例外安全的。如下所示:

void swapWith( MyType& other ) throw()
{
    // swap them members
}
void operator=( MyType other )
{
    swapWith( other );
}

在这里,复制构造函数创建正式的参数副本,任何异常都会发生在那里,因此在复制失败的情况下,复制构造函数也会集中清理。之后,两个对象的内容被交换,复制对象的析构函数负责清理该对象的内部内容。void结果类型还不是传统的,但在我看来,将代码和时间都浪费在支持有副作用的表达式上是不明智的,因为副作用是邪恶的。

现在,只需使用std::vector作为缓冲区,就可以避免所有这些

这就是我推荐的,真正简单的解决方案:使用std::vector

这是因为您的赋值运算符根本不安全。您需要打破旧状态作为最后步骤。考虑

Text& Text::operator= (const Text& other) {
    auto new_buffer = new char[other.bufferSize];
    std::copy(other.buffer, other.buffer + other.bufferSize, new_buffer);
    // Now consider whether or not you need to deallocate the old buffer.
    // Then set the new buffer.
    buffer = new_buffer;
    bufferSize = other.bufferSize;
    return *this;
}

这确保了如果遇到任何问题,可以保证Text对象始终有效,而且作为奖励,它是自分配安全的。所有写得好的赋值运算符都是自赋值安全的。

这通常与复制和交换联系在一起,即复制,然后交换,以确保安全。

这段代码将完美地运行

Text& Text::operator=(const Text& other) 
{ 
    if(this == &other) /* checks for self assignment */
         return *this;
    if(NULL == other.buffer)
         return *this;
    if(NULL != buffer) /* assuming buffer=NULL in constructor */
    {
         delete [] buffer;
         buffer = NULL;
    }
    bufferSize = other.getLength();
    buffer = new char[bufferSize+1];
    memset(buffer, 0, bufferSize+1);
    memcpy(buffer, other.buffer, bufferSize);
    return *this;
}

试试这个。。

经过一番思考和审查,我想我明白了。考虑到我需要编写一个由头文件指定的void函数,我必须从该头文件构造实现。我考虑了Drew Dormann、MvG以及其他人的意见,得出了以下结论:

void Text::operator= (const Text &other) 
{ 
    if (this != &other) // takes care of self-assignment
    { 
         delete [] buffer; // delete the old buffer
         bufferSize = other.bufferSize; // assign size variable
         buffer = new char[bufferSize + 1]; // create new buffer
         strcpy(buffer, other.buffer); // copy array
    }
}

这是有效的,我相信它是无内存泄漏的。