C++ 赋值重载:为什么使用相同的对象会导致程序出现问题?

C++ 赋值重载:为什么使用相同的对象会导致程序出现问题?,c++,C++,假设我们有以下情况: class StringClass { public: ... void someProcessing( ); ... StringClass& operator=(const StringClass& rtSide); ... private: char *a;//Dynamic array for characters in the string int capacity;//size of dyn

假设我们有以下情况:

class StringClass
{
public:
    ...
    void someProcessing( );
    ...
    StringClass& operator=(const StringClass& rtSide);
    ...
private:
    char *a;//Dynamic array for characters in the string
    int capacity;//size of dynamic array a
    int length;//Number of characters in a
};

StringClass& StringClass::operator=(const StringClass& rtSide)
{
    capacity = rtSide.capacity;
    length = rtSide.length;
    delete [] a;
    a = new char[capacity];

    for (int i = 0; i < length; i++)
       a[i] = rtSide.a[i];

    return *this;
}
我正在读的教科书(绝对C++)说,在
delete[]a之后“指针s.a随后未定义。赋值运算符已损坏对象s,此程序运行可能已中断。”

为什么操作员损坏了s?如果我们在删除s.a后立即对其进行重新注资,为什么会在程序中造成这样的问题,我们必须将函数重新定义为:

StringClass& StringClass::operator=(const StringClass& rtSide)
{
    if (this == &rtSide)
    //if the right side is the same as the left side
    {
        return *this;
    }
    else
    {
        capacity = rtSide.capacity;
        length = rtSide.length;
        delete [] a;
        a = new char[capacity];
        for (int i = 0; i < length; i++)
            a[i] = rtSide.a[i];

        return *this;
    }
}
StringClass&StringClass::operator=(常量StringClass&rtSide)
{
if(this==&rtSide)
//如果右侧与左侧相同
{
归还*这个;
}
其他的
{
容量=rtSide.capacity;
长度=rtSide.length;
删除[]a;
a=新字符[容量];
for(int i=0;i
如果将对象分配给自身,则
a
rt.a
都指向同一字符串,因此当执行
delete[]a
时,您将同时删除
a
rt.a
指向的内容;然后重新分配它,但是要在循环中复制(在自身上)的数据在
delete
中丢失了

现在,在循环中,您只需将
new
返回的内存中碰巧存在的任何垃圾复制到自身上


顺便说一句,即使使用自分配的“安全网”,也要检查分配操作符是否完全正常(例如,它不是异常安全的);定义“大三”(复制构造函数、赋值运算符、析构函数)的“安全”方法是使用“.”

考虑
rtSide.a
的值是多少,当您在坏
运算符=
中时

它与
this->a
相同,是您刚刚删除的值。访问非自有内存是未定义的行为,因此访问此->是未定义的行为(因为您刚刚释放了它)


显然,不做任何事情而不是为自己的成员创建所有实例的临时副本要有效得多。这与做
intx=5是相同的概念;int y=x;x=y

如果您自行分配,则在通过RHS参数将字符串复制到新分配的空间之前,可以通过LHS参数释放(
删除
)。这不是幸福的秘诀;这是未定义的行为,任何事情都可能发生。撞车是有可能的;如果你真的很不走运,它可能会起作用。

这是因为你首先删除了指针
delete[]a
然后稍后尝试从已删除的位置复制:

for (int i = 0; i < length; i++)
       a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
for(int i=0;i
请记住,它是您尝试从中复制的同一位置,您已将其删除。 因此,错误
您发布的后面的代码通过将自我分配作为单独的案例进行检查来解决此问题。

delete[]a;
delete [] a;
a = new char[capacity];

for (int i = 0; i < length; i++)
   a[i] = rtSide.a[i];
a=新字符[容量]; for(int i=0;i
这就是为什么。你可以这样想:

删除a指向的内容,然后分配新的内存块。新的内存块包含垃圾,垃圾将成为您的新数据。不要被
a[i]=rtSide.a[i]的循环所迷惑

记住,
this
rtSide
都会将您引导到同一个对象。使用
修改对象时,
rtSide
引用的对象将被修改。

为什么操作员已损坏
s
?当您删除[]a时,
,你说你不再对那个记忆感兴趣;您不会尝试读或写它。系统可能决定在该存储器中存储一些内务管理信息;如果你去读它,你可能会读到一些与你发布它之前不同的东西。即使系统没有修改它,你仍然在访问你说你不再感兴趣的数据,因此你欺骗了编译器,编译器讨厌被欺骗,并且会得到自己的回报。可能是因为你的程序崩溃了!
char* ca;
if (this == &rtSide) {
    ca = copy of rtSide.a or this->a;
} else {
    ca = rtSide.a;
}

//Do your assigning and whatnot

if (this == &rtSide) {
    delete[] ca;
}
for (int i = 0; i < length; i++)
       a[i] = rtSide.a[i]; //rtSide has already been deleted as 'this' and '&rtSide' are same.
delete [] a;
a = new char[capacity];

for (int i = 0; i < length; i++)
   a[i] = rtSide.a[i];