所以我有一个标准的C ++设置,其中包含一个存储另一个对象的对象。存储的对象完全拥有,它永远不会泄露到外面。该成员是非const。
class Container
{
private:
Contained item;
}
据我所知,当我的Container被实例化时,将在item
成员上调用默认构造函数,我不必在初始化列表中管理它。
我还能正确理解当我的对象被销毁时,item
上的dtor会被自动调用吗?
另一种选择是通过参考当然存储它
class Container
{
private:
Contained& item;
public:
Container() : Contained()
{
}
}
在这种情况下,我不知道我是否应该在dtor中delete
。
另一种选择是通过ptr存储它
class Container
{
private:
Contained* item;
public:
Container()
{
item = new Contained();
}
~Container()
{
delete item;
}
}
知道我的item
永远不会返回给调用者并且永远不会流入外部API而永远不会被重新分配,最好的方法是什么?正如我所提到的,item
成员不是const
(这将是一个自我调整大小的数据结构)。
答案 0 :(得分:2)
最简单的方法是存储对象本身。我想说,为此目的使用参考是令人困惑的。使用指针的一个优点是,您可以避免在头文件中定义Contained类型 - 您可以改为转发declare Contained,并将所有详细信息保存在.cpp文件中。
答案 1 :(得分:1)
第一种方式是我认为最好的方式(看起来你不需要对象进行懒惰构建)。第二种方式要求你从外部传入对象并保证它的生命周期,第三种方法实际上只有你想要延迟实例化(即只在第一次使用时创建对象)。
答案 2 :(得分:1)
在这种情况下,最好存储对象本身,是的。通过引用存储它只会为对象创建别名,因此您的类不是实际的所有者。通过指针存储是没用的,除非您的对象是基类,并且您可能想要存储派生对象。
答案 3 :(得分:0)
与Luchian Grigore相反,我会选择指针/引用方法:将封装对象存储为引用或指针允许您向前声明它,从而节省编译时间。
除此之外,它还允许您拥有init()
和destroy()
成员函数,这些函数将依次调用封装对象的构造函数和析构函数,以及执行其他部分的初始化。宾语。这样,可以通过init()
的返回值来处理错误的初始化。
答案 4 :(得分:0)
大多数情况下,您希望减少对类的依赖性。如果这个类构成了界面的一个组成部分(即使该成员是私有的),那么你可以假设使用你的类的任何人都将使用这个。
在这种情况下,将其作为成员变量是有道理的。
如果它是您的类的实现细节,您应该使用前向声明从用户隐藏此详细信息,因此请使用允许前向声明的类型。
它不太可能成为参考。必须在构造类时初始化引用,因此构造函数可能必须传入它引用的对象。用新的和解除引用来声明它会导致混乱。
如果它是一个指针,那么你的类可以使用析构函数来管理它的生命周期。在这种情况下,我经常使用原始指针,因为它很好地受到控制,我的析构函数可以愉快地删除它,假设我的类是不可复制的。
如果使用shared_ptr,则可以使用前向声明。但要注意你的语义现在是,如果你复制你的对象,所有的副本将有一个指向同一个底层对象的指针。如果这不是你想要的,shared_ptr可能是错误的。此外,如果在类不可复制时使用shared_ptr,则不会真正共享它。
因此,除非你能使用允许前向声明的unique_ptr,否则我会选择原始指针和不可复制的类。
如果你的成员确实仍然是一个实现细节但是非常标准的东西,比如地图或向量,那么在使用前向声明的范围内,不值得“封装它”,只包含其中包含的类型地图或矢量,但不是地图或矢量本身。