c++ 通过ref传递的共享指针,复制并移动到向量中

m0rkklqb  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(208)

我试图理解共享指针的以下哪种用法在将其插入向量时更有意义。
bar接受共享指针的常量引用,而foo接受副本。在这两种情况下,传入的参数都被移动到一个向量中。有趣的是,调用者中ause_count对于foobar仍然为2,这意味着向量存储了一个“副本”?
就像shared_ptr是由一个引用传递的,它的计数不会递增,一旦它被“移动”到一个vector中,它就会递增,这是否意味着vector没有存储对原始对象a的引用?

class A
{
    std::vector<std::shared_ptr<int>> _vec;

    public:
    void bar(const std::shared_ptr<int>& ptr)
    {
        _vec.emplace_back(std::move(ptr));
    }

    void foo(std::shared_ptr<int> ptr)
    {
        _vec.emplace_back(std::move(ptr));
    }
};

int main()
{
    auto sp = std::make_shared<int>();

    A a;
    // a.foo(sp);    // use_count = 2
    a.bar(sp);       // use_count = 2
}
nfg76nw0

nfg76nw01#

通过引用constshared_ptr传递给bar,这意味着不能通过该引用修改原始的shared_ptr
share_ptr移动需要修改moved-from shared_ptr以将其设置为不指向任何内容。
看到问题了吗?bar不能从ptr移动,所以它最终将其复制到向量中。ptr/sp仍然有效,并继续指向您在main中分配的inta._vec也持有相同intshared_ptr。因此use_count必须为2。
如果你真的想从sp移走,那么你应该修改bar以接受某种可变的引用,尽管你真的应该让它接受一个右值引用,因为a.bar(sp)导致sp无效会违背大多数程序员的期望:

class A
{
    std::vector<std::shared_ptr<int>> _vec;

    public:
    void bar(std::shared_ptr<int>&& ptr)
    {
        _vec.emplace_back(std::move(ptr));
    }
};

int main()
{
    auto sp = std::make_shared<int>();

    A a;
    a.bar(std::move(sp));
    // Here sp.use_count() is 0 because it was moved from
    // a._vec.back().use_count() will be 1 though
}

Demo
这限制了调用者总是将他们的shared_ptr移动到A中,当调用者想要放弃所有权时,像在foo中那样简单地通过值接受参数可能不会导致可测量的性能差异,而当他们不想放弃所有权时,则提供更大的灵活性。

k7fdbhmy

k7fdbhmy2#

在这两种情况下,传递给foo和bar的共享指针都被移动到了vector中,这意味着vector获得了共享指针管理的动态分配内存的所有权,而调用者中的共享指针不再管理任何内存。
foo和bar的区别在于foo获取共享指针的副本,而bar获取共享指针的常量引用。由于foo获取副本,因此共享指针的引用计数在传递给foo时会递增1。这意味着在foo被调用后,引用计数将为2。
相反,bar采用对共享指针的常量引用,因此引用计数在传递给bar时不递增。这意味着引用计数在调用bar后将保持为1。
总的来说,在这种情况下使用bar更有效,因为它不需要额外增加引用计数,但实际上性能上的差异可能很小。更重要的是,要为您的特定用例选择可读性和可维护性更强的方法。

相关问题