【问题标题】:keeping shared_ptr use_count() at 1保持 shared_ptr use_count() 为 1
【发布时间】:2021-04-10 21:09:22
【问题描述】:

我找不到与此问题类似的问题,如果我错过了,请直接找一个问题! 我正在尝试使用智能指针,并遇到了这种情况,我想将 use_count() 在 shared_ptr 对象中返回的值保持为 1(以练习优化代码)。这是我正在使用的 sn-p:

#include <iostream>
#include <memory>
#include <vector>

// testFunc: displays the use_count of each shared ptr in the list
void testFunc(const std::vector<std::shared_ptr<int>> &list) {
    // reference each shared ptr in the list and display their use_count
    for (auto &elem : list) {
        std::cout << elem.use_count() << std::endl;
    }   
} // testFunc()

int main() {
    // allocate shared ptr instance of an int
    auto sharedTest = std::make_shared<int>(11);

    // allocate another shared ptr instance of another int
    auto anotherSharedTest = std::make_shared<int>(22);

    // use std::move to prevent another copy of the shared ptrs from being created
    testFunc({ std::move(sharedTest), std::move(anotherSharedTest) }); 

    return 0;
} // main()

这个程序的输出是

2
2

因为两个共享 ptrs 的 use_count 都是 2。谁能告诉我为什么我不能将它们保持在 1?我怀疑在传递整个向量时将向量“传递”给testFunc 会创建每个共享ptr 的副本,但这让我感到惊讶,因为我通过引用传递向量。非常感谢任何输入!

【问题讨论】:

  • 这无论如何都不能回答你的问题,但是如果这里的目标是练习移动东西,为什么不使用像 unique_ptr 这样的只移动类型,你会得到一个编译时错误如果您尝试复制。
  • 我不确定答案,但我怀疑{ ... }std::initializer_list,然后将其参数复制到临时向量中。所以你有 2 个,一个在临时 initializer list 中,另一个在 temporary vector 中。在函数返回之前,临时的初始化器列表不会消失。
  • @AndersK 不是这样,它是 init_list。由于shared_ptrs 构造函数,std::move 确实会影响 use_count。
  • 你有你原来的共享指针,然后你创建了2个临时对象。一个初始化列表和一个向量。临时 initializer list 和临时 vector 都会保留一份 shared pointers 的副本。因此,如果您不使用 std::move,您将拥有 3(原件加上 2 个临时对象)。如果您移动,直到函数调用结束,您只有 2 个临时对象。
  • @v.p.它们纯粹是为了方便。认为{ ... } 是一个vector 并忘记它是促进vector 创建所需的自己的类型是很容易和诱人的。

标签: c++ c++17 smart-pointers


【解决方案1】:

问题是临时的initializer_list&lt;shared_ptr&gt; 保留了元素的副本,并且它一直存在到完整表达式(;)的末尾。

您无能为力,initializer_list 始终通过副本存储其元素。

作为一种解决方法,您可以预先构造向量:

std::vector<std::shared_ptr<int>> list{std::move(sharedTest), std::move(anotherSharedTest)};
testFunc(list);

应该打印1 1

【讨论】:

  • 哇!这行得通,我很感激你的意见。这个答案现在让我想知道使用 initializer list 的好处或用例会是什么,因为它总是按副本存储,直到语句返回。
  • 是的,这是initializer_list 的一个缺点,由于它的瞬态特性而经常被忽视。
【解决方案2】:

根据this answer,std::initializer_list 只允许 const 访问其元素。这意味着 std::vector 构造函数需要从列表中复制所有元素(因为 move 是非常量的)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-30
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 2022-12-12
    • 2016-07-22
    • 2020-10-08
    相关资源
    最近更新 更多