【问题标题】:Question about shallow copy in C++关于C++浅拷贝的问题
【发布时间】:2010-09-17 23:37:20
【问题描述】:

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

【问题讨论】:

    标签: c++ memory-management constructor


    【解决方案1】:

    跟进@[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)
      {
      }
    };
    

    【讨论】:

    • 您的赋值运算符不是异常安全的。查看最近关于复制和异常安全的问题:stackoverflow.com/questions/214891/…
    • Doh,好的,我修好了。你明白我的意思,那就是它是一种痛苦和难以纠正的意思,嗯
    • 使复制构造函数和 operator= 私有的最好方法是从 boost::noncopyable 继承。除非你确定它是可复制的,否则你应该对每一堂课都这样做。
    • 有了copy-and-swap这句成语,真的很容易做对(虽然效率有点低)
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      您将拥有 s 结构的两个副本,每个副本都有自己的 i 指针,但两个 i 指针将具有指向内存中相同地址的相同值 - 所以是的,它将是浅拷贝。

      【讨论】:

        猜你喜欢
        • 2010-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多