【问题标题】:Best way to append object to a vector of smart pointers?将对象附加到智能指针向量的最佳方法?
【发布时间】:2019-11-22 07:11:52
【问题描述】:

考虑以下类:

class A {
 public:
    A() {};
 protected:
    int m1;
    float m2;
    // ...
}

class B {
 public:
    B() { };
    void add1(std::shared_ptr<A> _obj) { 
        data.push_back(_obj); 
    };
    void add2(A* _obj) { 
        data.push_back(_obj); 
    };
    void add3(A& _obj) { 
        data.push_back(&_obj); 
    };
 private:
    std::vector<std::shared_ptr<A>> data;
}

B 类中的哪些方法addX 更适合/最佳实践将新指针传递给向量?考虑到 data 是非常量智能指针的向量,我知道不可能通过 const 引用传递对象或智能指针而不必“解除”它们,这是不可取的,被认为是不好的做法。但是,除非我弄错了,否则所有这些方法最终都会实例化shared_ptr,然后将其复制到向量中?它们之间有什么区别?

【问题讨论】:

  • 所有 3 个都有不同的含义,第 3 个实际上是错误的(我无法想象任何不危险的用例)。选择方法时必须考虑对象的所有权。哪一方应持有该对象的所有权? add 的来电者? B?两者都有?
  • 在这种情况下,所有权在设计上应该是共享的,因此我使用shared_ptr。然而,A 的实例被假定在B 的范围之外被实例化,但是在附加到成员向量之后,B 可以对其进行任何处理。
  • 选项 2 未使用共享所有权。您希望调用者将所有权传递给B,因为Bdelete 指针。您需要在文档中明确说明。
  • 请注意,您也可以传递 std::unique_ptr&lt;A&gt;std::weak_ptr&lt;A&gt;add1 可以接受
  • @Caleth 比普通的shared_ptr 有什么优势吗?例如,unique_ptr 是否更小,因此更易于移动?

标签: c++ parameter-passing smart-pointers


【解决方案1】:

如果您想确保您的 API 清楚地表明被调用者将获得所有权,唯一可行的方法是 add1。从签名中可以清楚地看出,无论你给它什么,被调用者都会保留它。

您可以使用std::move.emplace_back 来改进它:

void add1(std::shared_ptr<A> _obj) 
{ 
    data.emplace_back(std::move(_obj)); 
}

add2 具有误导性,因为原始指针可能暗示也可能不暗示所有权。有人可以将指针传递给堆栈分配的变量。

add3 有同样的问题,但更容易产生误导,因为非const 引用通常用于就地改变对象,而不是获取它的所有权。

【讨论】:

  • 感谢您的输入,但现代编译器不是已经避免在这些类型的简单函数中不必要的复制吗?我假设如果在调用add1 时创建了 smart_ptr 对象(例如 foo.add1(&bar),其中 bar 的类型为A),那么 push_back 是否已经就地创建了新条目?显然不是这样的。
  • @joaocandre 编译器会在不明显时忽略副本。 _obj 仍然存在于 add1 的其余部分。
  • @joaocandre:没有。只有一些非常特殊的情况会省略副本。
  • @VittorioRomeo 只是关于这个的另一个小细节,为什么在这里使用emplace_back 而不是push_back 有优势?
【解决方案2】:

add2 不好,因为函数转移所有权,不应该使用裸指针来完成。

add3 更糟糕,因为即使在 C++11 之前的约定中,通过传递引用来转移指针的所有权也是非惯用的。

add1 很好。从函数声明中可以清楚地看出谁拥有资源(它是共享的)。但是,您可以避免复制共享指针:

void add1(std::shared_ptr<A> _obj) { 
    data.push_back(std::move(_obj)); 
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-11
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-25
    • 2021-05-18
    相关资源
    最近更新 更多