C++;:作为引用或指针的基类型成员变量 我想知道什么是最好的方法来实现一个设计困境在C++ +…/P>

C++;:作为引用或指针的基类型成员变量 我想知道什么是最好的方法来实现一个设计困境在C++ +…/P>,c++,inheritance,class-members,C++,Inheritance,Class Members,我有一个类,它包含另一个类的Base类型的成员变量,创建的真实对象被创建为Base的派生的 类不需要修改这些变量,它只使用它们。其他人正在创建这些变量。这些派生的类还需要转到我的类中的容器(std::vector、QList等)类,因此它们应该执行适当的拷贝构造和赋值 所以,我想知道什么可能是最好的: 将成员变量创建为Base*,让我们来管理它们和它们使用的内存。这导致了经典的内存泄漏问题。。。有人只是忘记删除对象,当他们不再使用它了 将成员变量创建为基&,让我们祈祷它们在超出范围时不会消失 你

我有一个类,它包含另一个类的
Base
类型的成员变量,创建的真实对象被创建为
Base
派生的

类不需要修改这些变量,它只使用它们。其他人正在创建这些变量。这些
派生的
类还需要转到我的类中的容器(std::vector、QList等)类,因此它们应该执行适当的拷贝构造和赋值

所以,我想知道什么可能是最好的:


  • 将成员变量创建为
    Base*
    ,让我们来管理它们和它们使用的内存。这导致了经典的内存泄漏问题。。。有人只是忘记删除对象,当他们不再使用它了
  • 将成员变量创建为
    基&
    ,让我们祈祷它们在超出范围时不会消失

  • 你应该考虑所有权。谁拥有这些东西?如果这个问题没有明确的答案,您应该使用
    std::shared\u ptr
    (共享所有权)。如果有一个类拥有该对象,而其他所有类都只使用它们,那么您可以使用
    std::unique_ptr
    ,一个指针容器,如
    boost::ptr_vector
    ,或者如果没有多态性,则表示只拥有具体实例的类。在所有其他类中,可以使用指向该对象的普通指针(首选为类成员)或引用(首选为参数,如果不允许null)

    案例1——共有所有权

    class IWorkOnBaseObjects
    {
        std::vector<std::shared_ptr<Base>> mySubset;
    };
    
    class MeToo
    {
        std::shared_ptr<Base> iNeedThisOne;
    };
    
    类IWorkOnBaseObjects
    {
    std::向量mySubset;
    };
    梅托级
    {
    std::共享\u ptr在该电话中;
    };
    
    案例2

    class HomeOfBaseObjects
    {
        std::vector<std::uniqe_ptr<Base>> baseObjects;
    };
    
    class IWorkOnBaseObjects
    {
        std::vector<Base*> mySubset;
    };
    
    类对象
    {
    矢量基对象;
    };
    类IWorkOnBaseObjects
    {
    std::向量mySubset;
    };
    
    案例3

    class A : public Base{};
    class B : public Base{};
    
    class HomeOfAObjects
    {
        std::vector<A> aObjects;
    };
    
    class HomeOfBObjects
    {
        std::vector<B> bObjects;
    };
    
    class INeedABaseObject
    {
        Base* thisOne;
    };
    
    A类:公共基{};
    B类:公共基{};
    类对象
    {
    std::向量对象;
    };
    类对象
    {
    std::向量对象;
    };
    类IneedBaseObject
    {
    基*这个;
    };
    
    拥有引用成员变量总是一个糟糕的选择,因为编译器生成的赋值和移动赋值做了错误的事情,或者不是人们所期望的那样


    对于成员变量,请坚持使用指针或智能指针。

    我会使用指针,无论是对于向量(即
    向量
    ,而不是
    向量
    ),还是容器类,原因如下:

    • 如果将派生对象存储在向量中,该向量可能会被重新调整大小,从而导致所有对象“移动”到内存中的新位置。这将使所有未完成的指针和引用无效
    • 如果您的容器包含引用,您将无法像复制包含指针的容器那样轻松地复制它,因为引用只能在定义时绑定(因此在构造函数中通过
      MyClass::MyClass(int&a):memberA(a){}
      ,如果内存可用)
    • 指针可以根据需要通过其他方式(如set方法)进行更改,并且在缺少信息的情况下可以设置为null

    就所有权而言,jrok首先说:
    shared\u ptr
    是你的朋友。不要重新发明轮子,只要利用标准库为您简化事情即可。在这种情况下,你唯一需要担心的是循环指针(即,对象指向自身,所以总是有一个有效的指针)。(不是
    派生的
    ,这个类将有一个数据成员,它是指向
    基的指针或引用)需要值语义(这是另一种说法,“正确地复制和赋值”)

    如果是这样的话,那么引用成员变量几乎是不可能的,因为它们不能被重置。在有些奇怪的情况下,您仍然可以使用它们,但您也可以假设您不会使用它们,并使用指针

    引用数据成员有时对具有“实体语义”的类型有用(即,它们根本不赋值,也可能不复制),但它们仍然不能给您带来太多好处。它们还可以引诱您编写一个构造函数,该构造函数接受
    const Base&
    参数,并将其存储在引用数据成员[*]中

    谁拥有对象(并负责释放对象)完全独立于您是使用指针还是引用。对于您拥有的对象,可能有一个不使用引用的通用约定(应该有一个惯例,不要对你拥有的东西使用原始指针,你应该选择或编写一个合适的智能指针。智能指针类可以保存一个原始指针)。但这只是惯例。你不应该假设只有当你有一个指针时才管理内存

    小结:使用指针,然后单独决定如何管理内存


    [*]这是一个错误,因为最终会有人意外地在初始值设定项中使用临时对象,然后您的类及其引用数据成员的实例将比临时对象更长寿。因此,存储引用以供返回后使用的对象不应使用
    常量&
    参数,即使它们不修改对象。他们可以使用
    常量*
    来代替。在C++11中,我想如果还有一个右值引用重载,可以避免为临时对象选择
    常量和
    重载,但这不是我已经尝试过的。如果你在控制对象的生存时间方面有问题,Hansmad是正确的您应该与创建或管理它的人共享它的所有权。
    您有两个选项:
    1)
    boost::shared_ptr
    std::tr1::shared_ptr

    你可以很容易地使用f类
    boost::shared_ptr<Base> sharedObject( new Drived() );
    boost::shared_ptr<Base> validCopy( sharedObject );    // Ok share ownership
    Base* p = sharedObject.get();
    boost::shared_ptr<Base> invalidCopy( p );    // Error, can't create new shared_ptr from raw pointer