C++中浅拷贝的问题

5

假设我有一个结构体“s”,其中包含一个整型指针成员变量“i”。在s的默认构造函数中,我为i在堆上分配了内存。稍后在代码的其他部分,我通过值传递将s的实例传递给某个函数。这里我是在进行浅拷贝吗?假设我没有为s实现任何复制构造函数或赋值运算符或其他任何东西...只有默认构造函数。

3个回答

8

为了跟进@[don.neufeld.myopenid.com]所说的,这不仅仅是一个浅复制,而且它要么是(选择一种)内存泄漏,要么是悬挂指针。

// memory leak (note that the pointer is never deleted)
class A
{
  B *_b;
  public:
  A()
  : _b(new B)
  {
  }
};

// dangling ptr (who deletes the instance?)
class A
{
  B *_b;
  public:
  A()
  ... (same as above)

  ~A()
  {
    delete _b;
  }
};

为了解决这个问题,有几种方法。
在使用原始内存指针的类中,始终实现复制构造函数和operator=。
class A
{
  B *_b;
  public:
  A()
  ... (same as above)

  ~A()
  ...

  A(const A &rhs)
  : _b(new B(rhs._b))
  {
  }

  A &operator=(const A &rhs)
  {
    B *b=new B(rhs._b);
    delete _b;
    _b=b;
    return *this;
};

不用说,这是一件很重要的事情,而且有很多微妙之处需要注意。我甚至不确定我是否正确地完成了这个任务,因为我已经做了几次了。千万不要忘记要复制所有成员变量 - 如果您以后添加了一些新的成员变量,请不要忘记也加上它们!
在你的类中将复制构造函数和operator=设置为私有。这是“锁门”解决方案。它简单而有效,但有时过于保护。
class A : public boost::noncopyable
{
  ...
};

永远不要使用裸指针。这很简单而且有效。有很多替代方案:

  • 使用字符串类代替裸字符指针
  • 使用std::auto_ptr、boost::shared_ptr、boost::scoped_ptr等

示例:

// uses shared_ptr - note that you don't need a copy constructor or op= - 
// shared_ptr uses reference counting so the _b instance is shared and only
// deleted when the last reference is gone - admire the simplicity!
// it is almost exactly the same as the "memory leak" version, but there is no leak
class A
{
  boost::shared_ptr<B> _b;
  public:
  A()
  : _b(new B)
  {
  }
};

您的赋值运算符不是异常安全的。请参考有关复制和异常安全性的最近问题:https://dev59.com/JHVC5IYBdhLWcg3wrDRd - Luc Hermitte
好的,我修复了。你看我说的对吧,这个问题很烦人,而且很难搞定。 - 1800 INFORMATION
最好的方法是从boost::noncopyable继承来使复制构造函数和operator=私有化。除非你确定它是可复制的,否则你应该为每个类都这样做。 - CesarB
使用复制和交换技巧,即使它有点低效,也很容易做对。 - Luc Hermitte

5

是的,这是一次浅拷贝。现在你有两个s的副本(一个在调用者中,一个作为参数在堆栈中),它们都包含指向同一块内存的指针。


2
你将会有两份 s 结构体的拷贝,每个拷贝都有自己的 i 指针,但是这两个指针的值指向内存中相同的地址 - 所以是一种浅拷贝。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接