繁体   English   中英

C ++指针数据成员:谁应该删除它们?

[英]C++ Pointer data members: Who should delete them?

所以说我有这样一个类:

class A {
    public:
        A( SomeHugeClass* huge_object)
            : m_huge_object(huge_object) {}
    private:
        SomeHugeClass* m_huge_object;        
};

如果有人使用这样的构造函数:

A* foo = new A(new SomeHugeClass());

谁负责在构造函数中新建的对象上调用delete? 在这种情况下,调用A构造函数的范围只能删除foo,因为SomeHugeClass是匿名的。

但是,如果有人像这样使用构造函数呢?

SomeHugeClass* hugeObj = new SomeHugeClass();
A* foo = new A(hugeObj);

然后,调用者可以在某个时候调用delete hugeObj,对吗?

A的这种实现是否会破坏内存?

我正在研究一个以这种方式完成大量对象组合的项目,尽管我希望使用智能指针,但我必须与项目负责人讨论如何更改旧代码以便在我可以之前利用它。

我尽可能地尝试遵循这个简单的规则:调用new应该调用delete 否则,代码很快就会变得太乱,无法跟踪删除的内容和不删除的内容。

在你的情况下,如果A :: A收到指针,它不能删除它。 想想这个简单的案例:

SomeHugeClass* hugeObj = new SomeHugeClass();
A * a1 = new A(hugeObj);
A * a2 = new A(hugeObj);

A类不知道还有谁在使用该指针!

如果你想要A类来处理指针,它应该自己创建它。

当然,你可以处理这两种情况,但这可能是一种矫枉过正,如下所示:

A::A() : own_huge_object(true) {
    m_huge_object = new SomeHugeClass();
}
A::A(SomeHugeClass * huge_object ) : own_huge_object(false) {
    m_huge_object = huge_object;
}
A::~A() { if(own_huge_object) delete m_huge_object; }

在您的示例中,调用者应该负责删除huge_object因为构造函数可能抛出异常,并且不会调用A析构函数。 而且你的实现有内存泄漏,因为现在没有人调用delete

您可以使用shared_ptr ,如下所示:

class A {
    public:
        A( shared_ptr<SomeHugeClass> huge_object)
            : m_huge_object(huge_object) {}
    private:
        shared_ptr<SomeHugeClass> m_huge_object;        
};

在这种情况下,您不应该关心删除SomeHugeClass

为了这一行在下面

A* foo = new A(new SomeHugeClass());

不要导致内存泄漏,你可以确保在A类的析构函数中释放m_huge_object指向的内存。

A类定义可能如下所示:

class A {
  public:
    A(SomeHugeClass* huge_object)
        : m_huge_object(huge_object) {}
    ~A() { delete m_huge_object; }
  private:
    SomeHugeClass* m_huge_object;        
};

我不喜欢上面的内容是我更喜欢分配内存的人也应该是负责释放内存的人。 此外,还有基里尔指出的问题。 所以保持你对A类的定义,代码可以简单如下:

SomeHugeClass* hugeObj = new SomeHugeClass();
A* foo = new A(hugeObj); 
//some code
delete hugeObj;
delete foo;

这更像是一个设计问题。 传统上,当您将非常量指针传递给构造函数时,该对象应该释放指针。 如果您打算保留副本,请传递const引用。

另一种设计是这样的:SomeHugeClass通常不是那么大(例如指针),但拥有大量的内存:

class A
{
    SomeHugeClass m_;

public:
    A(SomeHugeClass x) { m_.swap(x); }
};

如果SomeHugeClass实现了有效的交换(交换指针),那么这种设计是可行的。 构造x在将其交换为m_之前生成x的副本,如果将临时对象传递给构造函数,则编译器可能会(并且通常将)删除该副本。

注意,someHugeClass可以在这里替换为smart_pointer<SomeHugeClass> ,当你将smart_pointer(new SomeHugeClass())传递给构造函数时,它会给你所需的语义,因为它是临时的。

编辑(为清晰起见......):最终代码可能看起来像

class A
{
    smart_ptr<SHC> m_;

public:
    A(smart_ptr<SHC> x) { m_.swap(x); }
};

当你调用A(new SHC(...))没有所需的行为(没有复制,当A被破坏时删除),当你调用A(smart_ptr<SHC>(a)) (执行a副本A(smart_ptr<SHC>(a)) ,当A被破坏时释放)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM