我应该通过引用、值或ptr来存储完全未封装的成员吗? < >我有一个标准的C++设置,它有一个对象,它存储另一个对象。存储的对象是完全拥有的,它从未泄漏到外部。该成员是非常量的 class Container { private: Contained item; }

我应该通过引用、值或ptr来存储完全未封装的成员吗? < >我有一个标准的C++设置,它有一个对象,它存储另一个对象。存储的对象是完全拥有的,它从未泄漏到外部。该成员是非常量的 class Container { private: Contained item; },c++,coding-style,private-members,C++,Coding Style,Private Members,据我所知,当我的容器被实例化时,默认构造函数将被调用到item成员上,我不必在初始值设定项列表中管理它。 此外,我是否正确理解,当我的对象被销毁时,将自动调用项目上的dtor 另一个选择当然是通过引用来存储它 class Container { private: Contained& item; public: Container() : Contained() { } } 在这种情况下,我不知道是否应该在dtor中删除它 另一个选择是通过ptr

据我所知,当我的容器被实例化时,默认构造函数将被调用到item成员上,我不必在初始值设定项列表中管理它。 此外,我是否正确理解,当我的对象被销毁时,将自动调用项目上的dtor

另一个选择当然是通过引用来存储它

class Container
{

private:
    Contained& item;

public:

    Container() : Contained()
    {

    }
}
在这种情况下,我不知道是否应该在dtor中删除它

另一个选择是通过ptr存储它

class Container
{
private:
    Contained* item;
public:
    Container()
    {
        item = new Contained();
    }

    ~Container()
    {
        delete item;
    }
}
知道我的项永远不会返回给调用者,也永远不会流入外部API,也永远不会被重新分配,那么最好的方法是什么?正如我提到的,item成员不是const
它将是一个自动调整大小的数据结构。

在我看来,第一种方法是最好的方法,它似乎不需要懒洋洋地构造对象。第二种方法要求您从外部传入对象,并保证对象的生命周期,第三种方法只有在您想要延迟实例化(即只在第一次使用时创建对象)时才是好的。

我认为第一种方法是最好的方法,似乎您不需要延迟构造对象。第二种方法要求您从外部传入对象,并保证对象的生命周期,第三种方法只有在您想要延迟实例化(即仅在第一次使用时创建对象)时才有效。

在这种情况下,最好存储对象本身,是的。通过引用存储它只会创建对象的别名,因此您的类不是实际的所有者。通过指针存储是无用的,除非您的对象是基类,并且您可能希望存储派生对象。

在这种情况下,最好存储对象本身,是的。通过引用存储它只会创建对象的别名,因此您的类不是实际的所有者。除非您的对象是基类,并且您可能希望存储派生对象,否则通过指针存储是无用的。

最简单的方法是存储对象本身。我想说,在这方面使用引用是令人困惑的。使用指针的一个优点是,您可以避免在头文件中定义包含的类型—您可以改为转发declare Contained,并将所有详细信息保存在.cpp文件中。

最简单的方法是存储对象本身。我想说,在这方面使用引用是令人困惑的。使用指针的一个优点是,您可以避免在头文件中定义包含的类型-您可以改为转发declare Contained,并将所有详细信息保留在.cpp文件中。

与Luchian Grigore相反,我会选择指针/引用方法:将封装的对象存储为一个或多个引用可以让您向前声明它,从而节省编译时间


除此之外,它还允许您使用init和destroy成员函数,这些函数将依次调用封装对象的构造函数和析构函数,以及执行对象其他部分的初始化。这样,一个错误的初始化可以通过init的返回值来处理。

与Luchian Grigore相反,我选择指针/引用方法:将封装的对象存储为一个或多个引用,可以让您向前声明它,从而节省编译时间


除此之外,它还允许您使用init和destroy成员函数,这些函数将依次调用封装对象的构造函数和析构函数,以及执行对象其他部分的初始化。这样,错误的初始化可以通过init的返回值来处理。

大多数情况下,您希望减少对类的依赖。如果该类构成接口的一个组成部分,即使该成员是私有的,那么您可以假设任何使用您的类的人都将使用该类

在这种情况下,将其作为成员变量是有意义的

当它是类的实现细节时,您应该通过使用转发声明对用户隐藏此细节,因此请使用允许转发声明的类型

它极不可能成为参考。引用必须在类的构造时初始化,因此构造函数可能必须传入它引用的对象。用new和dereference声明它将导致混乱

如果它是指针,则类可以使用析构函数管理其生存期。在这种情况下,我经常使用原始指针,因为它处于良好的控制之下,并且我的析构函数可以愉快地删除它,假设我的类是不可复制的

如果使用shared_ptr,则可以使用转发声明。但是要注意,现在的语义是,如果复制对象,所有副本都将具有 指向同一基础对象的指针。如果这不是您想要的,那么shared_ptr可能是错误的。此外,如果您在类不可复制时使用shared_ptr,那么它就不是真正的共享

因此,除非您可以使用允许转发声明的unique_ptr,否则我会选择原始指针和不可复制类


如果您的成员仍然是一个实现细节,但它是相当标准的,如映射或向量,则不值得将其封装到使用转发声明的程度,只封装映射或向量中包含的类型,而不封装映射或向量本身。

大多数情况下,您希望减少对类的依赖。如果该类构成接口的一个组成部分,即使该成员是私有的,那么您可以假设任何使用您的类的人都将使用该类

在这种情况下,将其作为成员变量是有意义的

当它是类的实现细节时,您应该通过使用转发声明对用户隐藏此细节,因此请使用允许转发声明的类型

它极不可能成为参考。引用必须在类的构造时初始化,因此构造函数可能必须传入它引用的对象。用new和dereference声明它将导致混乱

如果它是指针,则类可以使用析构函数管理其生存期。在这种情况下,我经常使用原始指针,因为它处于良好的控制之下,并且我的析构函数可以愉快地删除它,假设我的类是不可复制的

如果使用shared_ptr,则可以使用转发声明。但是要注意,现在的语义是,如果复制对象,所有副本都将有一个指向同一底层对象的指针。如果这不是您想要的,那么shared_ptr可能是错误的。此外,如果您在类不可复制时使用shared_ptr,那么它就不是真正的共享

因此,除非您可以使用允许转发声明的unique_ptr,否则我会选择原始指针和不可复制类


如果您的成员仍然是一个实现细节,但它是一个相当标准的东西,如映射或向量,则不值得将其封装到使用前向声明的程度,仅封装映射或向量中包含的类型,但不是地图或矢量本身。

这是有意义的-我不打算在它的下游进行动态投射,至少在这个阶段不这样做。这是有意义的-我不打算在它的下游进行动态投射,至少在这个阶段不这样做。你的第二个选项不是一个选项。它介于第一个和第三个之间,但是如果第三个在这种情况下,构造函数和析构函数的实现应该在编译单元中,而不是在类头中,并且必须向前声明类型。第二个不是选项。它介于第一个和第三个之间,但是如果第三个是构造函数和析构函数的实现,那么在这种情况下应该在编译单元中,而不是在类头中,并且必须向前声明类型。+1回答得好。请注意,指针解决方案接近常用的解决方案,因为它允许您向用户隐藏一些实现细节。事实上,PIMPL解决方案基于这种方法,但有点扩展和细化。好的,这就是我将使用的then-value成员。非常感谢+回答得好。请注意,指针解决方案接近常用的解决方案,因为它允许您向用户隐藏一些实现细节。事实上,PIMPL解决方案基于这种方法,但有点扩展和细化。好的,这就是我将使用的then-value成员。非常感谢!