我有一个关于赋值运算符的问题(如果已经在另一篇文章中回答过,请道歉)。
据我理解赋值运算符,假设将一个对象的值赋给另一个对象,例如
class A {
public:
A();
A& operator=(const A& rhs)
{
b = rhs.b;
return *this;
}
private:
B b;
};
现在,如果类包含指针,那么在赋值运算符中分配新内存似乎是常见的做法。这使得赋值运算符更加复杂,因为需要更加谨慎,例如
class A {
public:
A() : b(0)
{
b = new B;
}
A& operator=(const A& rhs)
{
if (this != &rhs) {
B* b1 = 0;
try {
b1 = new B(*rhs.b);
}
catch {
delete b1;
throw;
}
delete b;
b = b1;
}
return *this;
}
private:
B* b;
};
所以我的问题是:为什么不分配指向的现有对象的值,即通过调用B的赋值运算符重用内存,就像b不是指针一样(参见我的第一个例子)?然后分配看起来像这样
class A {
public:
A() : b(0)
{
b = new B;
}
A& operator=(const A& rhs)
{
*b = *rhs.b;
return *this;
}
private:
B* b;
};
这更加简单,完全符合我对赋值运算符的期望。
此外,我至少可以想到一个更复杂的赋值运算符会让我遇到麻烦的例子:如果A类有一个返回b的成员函数
const B* A::GetB() const
{
return b;
}
然后以下代码将留下一个悬空指针
A a1, a2;
const B* my_b = a1.GetB();
a1 = a2; // this leaves my_b dangling!
非常感谢您的评论。谢谢!
答案 0 :(得分:2)
您应该始终尽可能重用现有内存。在这种情况下,只有当您确定b
指向有效内存时,才应重用现有内存。
答案 1 :(得分:1)
这取决于手头的确切情况。通常,重用内存是一种好习惯,但实际上,当您尝试分配不同大小的内部数组等时,最好重新分配或删除/新建。
请注意,仍然需要在开头进行自我应对检查,以避免A = A
相似的情况。
答案 2 :(得分:1)
我想不出你不应该试图这样做的任何理由。我发现删除内存的示例是由于类型本身不可复制的事实。如果你有一个class属性并且它是一个指向可复制类型的指针,那么你的建议应该在概念上起作用(意味着你只发布了一个部分剪辑,所以我并不是说你的例子中的内容是完美的)。一些较旧的示例显示了如何使用char *和int *或其他类型的动态数组。但是,现代C ++程序员应该尝试使用std :: string和容器类。现在我们也有智能指针,这样你就可以拥有共享指针,而不必担心悬挂引用或担心哪个对象真的是它的拥有者。以下是我的意思的一个例子。该示例确实使用了模板,但副本就好像T是一个c数组(不是容器类)一样,因此必须像第一个例子那样进行深度复制。
http://www.cplusplus.com/articles/y8hv0pDG/