简体   繁体   English

我们如何从成员函数返回unique_pointer成员?

[英]How do we return a unique_pointer member from a member function?

I have a base class with a pointer member. 我有一个带有指针成员的基类。 I would have to make an educated guess to determine whether it should be an unique_ptr or a shared_ptr . 我必须做出有根据的猜测,以确定它应该是unique_ptr还是shared_ptr None of them seems to solve my particular use case. 他们似乎都没有解决我的特定用例。

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
};

The base class has been derived onto Derived1 and Derived2 . 基类已派生到Derived1Derived2 The former returns the unique_ptr member pInt where the later returns a local unique_ptr object. 前者返回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 's implementation of get would not implicitly transfer the ownership as the member pointer variable is not an eXpiring value, where as the Derived2 's implementation can. Derived1的get实现不会隐式转移所有权,因为成员指针变量不是eXpiring值,而Derived2的实现可以。 This behaviour is well documented in the standard 标准中详细记录了此行为

see 12.8 §34 and §35: 见12.8§34和§35:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object [...] This elision of copy/move operations, called copy elision, is permitted [...] in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type [...] 当满足某些条件时,允许实现省略类对象的复制/移动构造[...]复制/移动操作的省略,称为复制省略,允许在...的返回语句中。具有类返回类型的函数,当表达式是非易失性自动对象的名称时,具有与函数返回类型相同的cv-nonqualified类型[...]

When the criteria for elision of a copy operation are met and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. 当满足复制操作的省略标准并且要通过左值指定要复制的对象时,首先执行用于选择复制的构造函数的重载决策,就好像该对象由右值指定一样。

Nevertheless, if I explicitly transfer the ownership via the std::move , the member pointer would be unusable in the future. 然而,如果我通过std::move显式转移所有权,则成员指针将来将无法使用。

Alternatively, I would have to make the definition of the pointer as shared_ptr but that would be an extra overhead for the implementation of Derived2::get . 或者,我必须将指针的定义设置为shared_ptr但这将是Derived2::get实现的额外开销。

Note It should be considered that the occurrence of Derived2::get is more compared to Derived1::get so the design decision of using std:: shared_ptr can have a considerable relative impact. 注意应该考虑Derived2::get的出现与Derived1::get比较,因此使用std:: shared_ptr的设计决策会产生相当大的相对影响。

Your Derived1 case cannot be handled the way you want by unique_ptr . 您的Derived1案例无法按照您想要的方式处理unique_ptr You want multiple smart pointers to the same resource. 您需要多个智能指针指向同一资源。 unique_ptr is simply not an option for that. unique_ptr根本不是一个选项。 There's no way around that. 没有办法解决这个问题。

You could stick with a unique_ptr member, but make your function return a raw pointer. 你可以坚持使用unique_ptr成员,但是让你的函数返回一个原始指针。

virtual int *get() = 0;

This is troublesome for your Derived2 class, because it is not clear whether the caller should free the pointed-to memory. 这对于Derived2类来说很麻烦,因为不清楚调用者是否应该释放指向的内存。 I recommend you do not do this. 我建议你要这样做。

You could use a shared_ptr member, as you suggested, and make your function return that. 您可以按照建议使用shared_ptr成员,并使您的函数返回该成员。 This is fully functional in your Derived2 class, but as you point out, sub-optimal. 这在Derived2类中完全Derived2 ,但正如您所指出的那样,次优。

It is still the cleanest solution, though. 不过,它仍然是最干净的解决方案。 For callers that only know they've got a Base , you need some way of informing them (either manually or through the returned type) what they should do when they're done with get() 's result, so you cannot return unique_ptr<int> anyway. 对于只知道他们有Base调用者,你需要一些方法来通知他们(手动或通过返回的类型)当他们完成get()的结果时他们应该做什么,所以你不能返回unique_ptr<int>无论如何unique_ptr<int>

The only way a function returning unique_ptr<int> could be useful is if the caller already knows you've got a Derived2 . 返回unique_ptr<int>的函数唯一有用的方法是调用者已经知道你有Derived2 But then, you can just add a new member: 但是,您可以添加一个新成员:

virtual shared_ptr<int> get() {
  return get_unique();
}
virtual unique_ptr<int> get_unique() {
    std::unique_ptr<int> pInt(new int());
    return pInt;
}

I would only do that if profiling shows that the shared_ptr<int> get() member actually adds measurable overhead, though. 我只会这样做,如果分析显示shared_ptr<int> get()成员实际上增加了可衡量的开销。 There's a good chance that your shared_ptr<int> implementation is sufficient, performance-wise, and then readibility should probably be a reason for not adding a new member. 您的shared_ptr<int>实现很有可能在性能方面是充分的,然后可读性应该是添加新成员的原因。

The purpose of unique_ptr is to point to a resource from a unique place. unique_ptr的目的是指向来自唯一位置的资源。 If you need to point to this resource from multiple places, unique_ptr is no longer appropriate. 如果您需要从多个位置指向此资源,则unique_ptr不再适用。 You should use shared_ptr in that case. 在这种情况下,您应该使用shared_ptr。
If releasing ownership of the resource is appropriate for your logic, then just use: 如果释放资源的所有权适合您的逻辑,那么只需使用:

unique_ptr<int> get()
{
   return move(pInt);// this will move the ownership of the resource away from the member field
}

... but from now on, the pInt is no longer valid. ......但从现在开始,pInt已不再有效。

If you are careful with resources (if you are not worried of dangling pointers), than just return raw pointer to the resource (but please don't prefer this to use of shared_ptr). 如果你小心资源(如果你不担心悬空指针),那么只需返回指向资源的原始指针(但请不要使用shared_ptr)。

In case of using shared_ptr, be careful of cyclic dependency, use weak_ptr do counter it. 在使用shared_ptr的情况下,要小心循环依赖,使用weak_ptr做反计数。 Here is something about it: 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 以下是它的内容: http//geekwentfreak-raviteja.rhcloud.com/blog/2014/07/06/c11-how-to-create-cyclic-dependencies-with-shared_ptr-and-how-to-avoid-他们/?_ sm_au_ = irVM6PVF1TR4nGMW

Post edit: When you use unique_ptr as a member field, you are loosing copy constructor, because unique_ptr cannot be copied. 编辑后:当您使用unique_ptr作为成员字段时,您将丢失复制构造函数,因为无法复制unique_ptr。 FYI FYI

But still, use of unique_ptr seems to me as extra overhead already, in which just use shared_ptr or int directly. 但是,在我看来,使用unique_ptr作为额外的开销,只需直接使用shared_ptr或int。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM