【问题标题】:Understanding when shared_ptr reference counts are incremented when passing into a function了解当传递给函数时 shared_ptr 引用计数何时增加
【发布时间】:2020-05-11 03:29:39
【问题描述】:

我有以下Container

template <typename T>
class Container
{
private:
    std::vector<std::shared_ptr<T>> items_;
public:
    void addItem(std::shared_ptr<T> item)
    {
        std::cout << "useCount addItem pre: " << item.use_count() << std::endl;
        items_.push_back(std::move(item));
        std::cout << "useCount addItem post: " << item.use_count() << std::endl;
    }
};

我这样称呼它

int main(int argc, char** argv) {
    std::unique_ptr<Container<std::string>> container = std::make_unique<Container<std::string>>();

    std::shared_ptr<std::string> s = std::make_shared<std::string>("hello");

    std::cout << "useCount main pre: " << s.use_count() << std::endl;

    container->addItem(s);

    std::cout << "useCount main post: " << s.use_count() << std::endl;

    return 0;
}

这是我得到的输出

useCount main pre: 1
useCount addItem pre: 2
useCount addItem post: 0
useCount main post: 2

一行一行...

  1. 有道理,s 定义后只有一个引用

  2. 有道理,s 被复制到 item,所以它的引用计数增加 1

  3. 我已将item 的所有权授予items_,因此引用计数不应更改,因为addItem 已放弃所有权并将其转移给items_。我希望引用计数为 2,一次来自 main,一次来自 items_。相反,它是 0。

  4. 只要一个引用来自 main 并且一个引用来自 items_ 就有意义。

感谢您的澄清!

【问题讨论】:

  • 在#3 中,您正在查看一个已被移出的变量。 item 持有一个空指针。
  • @IgorTandetnik 它不为空。它是空的。保存 null 的非空共享指针和不保存任何内容的空共享指针之间存在(非常细微的)区别。

标签: c++ c++11 shared-ptr smart-pointers


【解决方案1】:

共享指针被移出后,它应该是空的。空共享指针的使用次数为0。

从另一个角度来看,您期望在那时,mainitems_ 拥有该对象(这是正确的),但如果它们被计入指针 use_countitem ,那么这将是拥有该对象的总共三个共享指针。这与您对 2 的期望相矛盾。当然,这是因为item 不再拥有该对象,因此它的使用计数实际上不再与拥有它的其他指针相关。

【讨论】:

  • 谢谢@eeronika 我很欣赏你的回答显示了我的逻辑缺陷,但我接受了@Chipster 的回答,因为它提供了一些关于std::shared_ptr 行为的额外信息
【解决方案2】:

std::move 将项目从该变量中移到另一个变量中。正如一位作者所说,它是“has explicit license to pillage [the variable]”。对于most std objects,它将原始对象置于未指定状态。但是,它出现 std:shared_ptr is an exception 是因为它使对象处于空状态。

所有这一切归结为,您不能在移动后将item 视为对s 的相同引用。它处于不同的状态,存储着其他东西。这就是您的引用计数关闭的原因。

如果你这样做了:

std::cout << "useCount addItem post: " << items_.back().use_count() << std::endl;

你会得到2的预期输出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 1970-01-01
    • 2014-11-26
    • 2012-09-27
    • 1970-01-01
    • 2012-08-13
    • 2021-10-17
    相关资源
    最近更新 更多