我想知道在C ++中实现设计困境的最佳方法是什么......
我有一个类,其中包含另一个类的Base
类型的成员变量,并且创建的真实对象创建为Derived
Base
。
该类不需要修改这些变量,它只使用它们。其他人正在创建这些变量。这些Derived
类还需要转到我的类中的容器(std :: vector,QList等)类,因此它们应该执行正确的复制构造和赋值。
所以,我想知道什么是最好的:
Base*
,让我们管理它们以及它们使用的内存。这导致了经典的内存泄漏问题......当有人不再使用它时,有人会忘记删除它。Base&
,让我们祈祷,当它们超出范围时,它们不会消失。答案 0 :(得分:1)
拥有引用成员变量总是一个糟糕的选择,因为编译器生成的赋值和移动赋值做错了,或者不是人们所期望的。
坚持使用成员变量的指针或智能指针。
答案 1 :(得分:1)
@hansmaad是正确的,如果您在控制对象的生命周期方面遇到问题,您应该与创建或管理对象的人共享其所有权。
您有2个选择:
1)boost::shared_ptr
或std::tr1::shared_ptr
您可以轻松地将此类用于任何类型Base
而无需更改Base
,但如果您在多线程环境中工作,则很难实现shared_ptr
的线程安全,并且不要忘记如果使用其中一个类创建一个对象共享,则不应直接管理对象的生命周期,从原始指针创建新的共享对象是不合法的,并且应始终复制构造共享对象。例如:
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
2)boost::intrusive_ptr
您可以轻松地使其成为线程安全的,您可以将其作为原始指针或智能指针传递,因为它可以从原始指针构造,因为引用计数是在类中实现的,但您应该更改类的定义并添加引用计数机制< / p>
答案 2 :(得分:0)
你应该考虑所有权。你拥有那些物品?如果对此问题没有明确答案,则应使用std::shared_ptr<Base>
(共享所有权)。如果有一个拥有该对象的类而其他所有对象只使用它们,则可以使用std::unique_ptr<Base>
,像boost::ptr_vector
这样的指针容器,或者如果没有多态,那么只拥有类的具体实例。在所有其他类中,您可以使用普通指针(首选为类成员)或引用(如果不允许为null,则优先使用参数)。
案例1 - 共享所有权
class IWorkOnBaseObjects
{
std::vector<std::shared_ptr<Base>> mySubset;
};
class MeToo
{
std::shared_ptr<Base> iNeedThisOne;
};
案例2
class HomeOfBaseObjects
{
std::vector<std::uniqe_ptr<Base>> baseObjects;
};
class IWorkOnBaseObjects
{
std::vector<Base*> 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;
};
答案 3 :(得分:0)
我会选择指针,包括你的矢量(即vector<Base *>
,而不是vector<Base>
)和容器类,原因如下:
MyClass::MyClass(int &a) : memberA(a) {}
,如果内存服务) 就所有权而言,jrok是第一个说出来的:shared_ptr<>
是你的朋友。不要重新发明轮子,只需使用标准库来简化您的工作。在这种情况下,你唯一需要担心的是圆形指针(即,对象指向自身,所以总是有一个有效的指针)。
答案 4 :(得分:0)
使用引用成员变量时要考虑的第一件事是你的类(不是Derived
,将要有一个指针的数据成员或对Base
的引用的类)是否需要值语义(这是另一种说法,“复制和分配正确”)。
如果是这样,那么引用成员变量或多或少都会立即解决,因为它们无法重新定位。有些奇怪的情况你无论如何都可以使用它们,但你可以假设你不会,并使用指针。
参考数据成员偶尔会对具有“实体语义”的类型有用(也就是说,它们根本不会分配,可能会也可能不会复制),但它们仍然不会给你带来很多好处。他们还可以引发您编写带有const Base&
参数的构造函数并将其存储在引用数据成员[*]中的错误。
谁拥有该对象(并负责释放它)完全独立于您是使用指针还是引用。可能有一个普遍的惯例是不要对你拥有的东西使用引用(并且应该是一个不使用原始指针用于你拥有的东西的约定,你应该选择或编写一个合适的智能指针。智能指针类可以保持原始指针)。但这只是惯例。当且仅当你有一个指针时,你不应该假设你管理内存。
摘要:使用指针,然后单独决定如何管理内存。
[*]这是一个错误,因为最终有人会意外地在初始化程序中使用临时对象,然后具有其引用数据成员的类的实例将比临时对象更长。因此,在返回后存储引用以供使用的内容不应采用const &
参数,即使它们不修改对象也是如此。他们可以改为const *
。在C ++ 11中,我认为如果还存在rvalue引用重载,它们可能没问题,以防止为临时选择const&
重载,但这不是我已经尝试过的。