我有一个带有指针成员的基类。我必须做出有根据的猜测,以确定它应该是unique_ptr
还是shared_ptr
。他们似乎都没有解决我的特定用例。
class Base
{
public:
Base(): pInt(std::unique_ptr<int>(new int(10))) {};
virtual std::unique_ptr<int> get() = 0;
//Base(): pInt(std::shared_ptr<int>(new int(10))) {}; // Alternate implementation
//virtual std::shared_ptr<int> get() = 0; // Alternate implementation
private:
std::unique_ptr<int> pInt;
//std::shared_ptr<int> pInt; // Alternate implementation
};
基类已派生到Derived1
和Derived2
。前者返回unique_ptr
成员pInt
,后者返回本地unique_ptr
对象。
class Derived1: public Base
{
public:
Derived1() {};
virtual std::unique_ptr<int> get()
{
//return std::move(pInt); Will compile but the ownership is lost
return pInt;
}
private:
std::unique_ptr<int> pInt;
};
class Derived2: public Base
{
public:
Derived2() {};
virtual std::unique_ptr<int> get()
{
std::unique_ptr<int> pInt(new int());
return pInt;
}
private:
std::unique_ptr<int> pInt;
};
Derived1
的get实现不会隐式转移所有权,因为成员指针变量不是 eXpiring 值,而Derived2
的实现可以。标准
见12.8§34和§35:
当满足某些条件时,允许省略实现 复制/移动类对象的构造[...]这个省略 复制/移动操作,称为复制省略,允许在...中 函数中的return语句,具有类返回类型,当时 expression是具有的非易失性自动对象的名称 与函数返回类型[...]
相同的cv-unqualified类型当满足复制操作的省略标准时 要复制的对象由左值,重载决策指定 选择首先执行复制的构造函数就好了 对象由右值指定。
尽管如此,如果我通过std::move
明确转移所有权,则成员指针将来将无法使用。
或者,我必须将指针定义为shared_ptr
,但这将是Derived2::get
实现的额外开销。
注意应该考虑将Derived2::get
的出现与Derived1::get
进行比较,因此使用std:: shared_ptr
的设计决策会产生相当大的相对影响。
答案 0 :(得分:5)
Derived1
unique_ptr
案件无法按照unique_ptr
的方式处理。您需要多个智能指针指向同一资源。 unique_ptr
根本不是一个选项。没有办法解决这个问题。
你可以坚持使用virtual int *get() = 0;
成员,但让你的函数返回一个原始指针。
Derived2
对于shared_ptr
类来说这很麻烦,因为不清楚调用者是否应该释放指向的内存。我建议你不要这样做。
您可以按照建议使用Derived2
成员,并让您的函数返回该成员。这在您的Base
课程中完全有效,但正如您所指出的那样,次优。
但它仍然是最干净的解决方案。对于只知道他们有get()
的来电者,您需要某种方式通知他们(手动或通过返回的类型)他们应该做什么。完成了unique_ptr<int>
的结果,因此无论如何都无法返回unique_ptr<int>
。
返回Derived2
的函数唯一有用的方法是调用者已经知道你有virtual shared_ptr<int> get() {
return get_unique();
}
virtual unique_ptr<int> get_unique() {
std::unique_ptr<int> pInt(new int());
return pInt;
}
。但是,你可以添加一个新成员:
shared_ptr<int> get()
如果分析显示shared_ptr<int>
成员实际上增加了可衡量的开销,我只会这样做。您的{{1}}实施充分,性能方面,然后可读性可能是不添加新成员的原因。
答案 1 :(得分:0)
unique_ptr的目的是指向来自唯一位置的资源。如果您需要从多个位置指向此资源,则unique_ptr不再适用。在这种情况下你应该使用shared_ptr 如果释放资源的所有权适合您的逻辑,那么只需使用:
unique_ptr<int> get()
{
return move(pInt);// this will move the ownership of the resource away from the member field
}
......但从现在开始,pInt已不再有效。
如果您对资源非常小心(如果您不担心悬空指针),那么只需返回指向资源的原始指针(但请不要使用shared_ptr)。
如果使用shared_ptr,请注意循环依赖,请使用weak_ptr来对抗它。以下是它的内容:http://geekwentfreak-raviteja.rhcloud.com/blog/2014/07/06/c11-how-to-create-cyclic-dependencies-with-shared_ptr-and-how-to-avoid-them/?_sm_au_=irVM6PVF1TR4nGMW
发布编辑: 当您使用unique_ptr作为成员字段时,您将丢失复制构造函数,因为无法复制unique_ptr。 FYI
但是,在我看来,使用unique_ptr作为额外开销,只需直接使用shared_ptr或int。