赋值运算符是否应为数据成员分配新内存或重用现有内存?

时间:2014-04-07 20:04:15

标签: c++ pointers memory

我有一个关于赋值运算符的问题(如果已经在另一篇文章中回答过,请道歉)。

据我理解赋值运算符,假设将一个对象的值赋给另一个对象,例如

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!

非常感谢您的评论。谢谢!

3 个答案:

答案 0 :(得分:2)

您应该始终尽可能重用现有内存。在这种情况下,只有当您确定b指向有效内存时,才应重用现有内存。

答案 1 :(得分:1)

这取决于手头的确切情况。通常,重用内存是一种好习惯,但实际上,当您尝试分配不同大小的内部数组等时,最好重新分配或删除/新建。

请注意,仍然需要在开头进行自我应对检查,以避免A = A相似的情况。

答案 2 :(得分:1)

我想不出你不应该试图这样做的任何理由。我发现删除内存的示例是由于类型本身不可复制的事实。如果你有一个class属性并且它是一个指向可复制类型的指针,那么你的建议应该在概念上起作用(意味着你只发布了一个部分剪辑,所以我并不是说你的例子中的内容是完美的)。一些较旧的示例显示了如何使用char *和int *或其他类型的动态数组。但是,现代C ++程序员应该尝试使用std :: string和容器类。现在我们也有智能指针,这样你就可以拥有共享指针,而不必担心悬挂引用或担心哪个对象真的是它的拥有者。以下是我的意思的一个例子。该示例确实使用了模板,但副本就好像T是一个c数组(不是容器类)一样,因此必须像第一个例子那样进行深度复制。
http://www.cplusplus.com/articles/y8hv0pDG/