赋值重载:为什么使用相同的对象会导致程序中出现问题
Assignment overloading: why does using the same object cause problems in the program?
>假设我们有以下内容:
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;
}
我的问题是:为什么当我们尝试将对象分配给自身时,这种重载赋值运算符的实现会导致问题,例如:
StringClass s;
s = s;
我正在阅读的教科书(绝对C++)说,在delete [] a;
"指针s.a是未定义的。 赋值运算符损坏了对象,程序的运行可能被破坏了。
为什么运算符损坏了 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;
}
}
如果你将一个对象分配给它,a
和rt.a
都指向同一个字符串,所以当你这样做delete [] a
时,你正在删除a
和rt.a
指向的内容; 然后你确实重新分配它,但你要在循环中复制的数据(在自己身上)在delete
中丢失了。
现在在循环中,您只需复制new
自身返回的内存中的任何垃圾。
也不是完全可以的(例如,它不是异常安全的);定义"三巨头"(复制构造函数,赋值运算符,析构函数)的"安全"方法是使用"复制和交换习惯用法"。
如果你是自分配的,你通过LHS参数释放(delete
)字符串,然后再通过RHS参数将其复制到新分配的空间。这不是幸福的秘诀;这是未定义的行为,任何事情都可能发生。 崩溃是合理的;如果你真的不走运,它看起来可能会起作用。
当你在破碎的operator=
内时,考虑一下rtSide.a
的值是多少。
它和this->a
一样,你刚刚破坏的值。 访问非拥有内存是未定义的行为,因此访问 this->a 是未定义的行为(因为您刚刚释放了它)。
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i]; //Invalid when this->a == rtSide.a
//because rtSide.a is no longer owned by your program.
如果您确实想这样做,则必须在删除之前复制 :
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;
}
显然,不执行任何操作比临时复制所有实例自己的成员要高效得多。 这与做int x = 5; int y = x; x = y;
的概念相同
这是因为您首先删除了指针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.
请记住,它与您尝试从中复制的位置相同,您已经删除了该位置。因此,错误!
您发布的更高代码通过将自分配作为单独的案例进行检查来解决此问题。
delete [] a;
a = new char[capacity];
for (int i = 0; i < length; i++)
a[i] = rtSide.a[i];
这就是原因。可以这样想:
删除指向的任何内容,然后分配新的内存块。新的内存块包含垃圾,这些垃圾将成为您的新数据。不要被只将垃圾复制到自身上的循环a[i] = rtSide.a[i];
混淆。
请记住,this
和rtSide
都会引导您找到同一个对象。使用 this
修改对象时,将修改rtSide
引用的对象。
- C++程序问题:抛出'std::invalid_argument'实例后终止调用
- 测试外壳,插入和快速的程序问题
- Mongodb c ++驱动程序问题
- 输出中的特定递归反向程序问题
- C++ std::endl 的多线程程序 I/O 问题
- 我如何利用核心文件在C/C 中找到应用程序问题
- 套接字 TCP 服务器程序问题
- C++,结构数据库程序问题
- visual c++程序问题
- C++多个程序问题(rand、转换、崩溃)
- 非常基本的C++程序问题 - 二进制表达式的操作数无效
- C++练习车辆程序问题 - 初学者编程
- 关于堆和堆栈应用程序问题
- Boost asio:io服务在销毁步骤中被阻止了更多的处理程序问题
- 使用链接linux编译GLFW应用程序问题
- C++计算器程序.问题
- 基于WIndows - manifest的ETW提供程序问题
- 求1到100之间质数的程序问题
- 文件加载程序问题
- mfcc++托盘应用程序问题