在range-based for循环中使用shared_ptr指向std::vector

9

我写了一个C++函数,用于汇集一些数据并返回指向新分配的包含数据的std::vectorstd::shared_ptr。类似于这样的内容:

std::shared_ptr<std::vector<int>> shared_ptr_to_std_vector_of_ints()
{
    auto v = std::make_shared<std::vector<int>>();
    for (int i = 0; i < 3; i++) v->push_back(i);
    return v;
}

我试图使用基于范围的for循环遍历向量的内容,但它表现得好像向量是空的。经过一番摆弄后,我发现通过将从函数返回的值赋给本地变量,然后在循环中引用该值,我可以使其按照我预期的方式运行:

// Executes loop zero times:
std::cout << "First loop:" << std::endl;
for (int i : *shared_ptr_to_std_vector_of_ints()) std::cout << i << std::endl;

// Prints three lines, as expected
std::cout << "Second loop:" << std::endl;
auto temp = shared_ptr_to_std_vector_of_ints();
for (int i : *temp) std::cout << i << std::endl;

这段代码输出以下内容:
First loop:
Second loop:
1
2
3

为什么第一个版本不起作用?

我正在macOS Sierra 10.12.6上使用Xcode。 我相信它使用LLVM 9.0编译c ++代码。


2
你真的需要在 std::vector 周围使用 shared_ptr 吗?(因为 std::vector 已经管理内存)?(特别是在提供的用法中)。 - Jarod42
1个回答

9
请注意,shared_ptr_to_std_vector_of_ints 是按值返回的,因此它返回的是一个临时对象。 范围for循环 相当于:
{
  init-statement
  auto && __range = range_expression ; 
  auto __begin = begin_expr ;
  auto __end = end_expr ;
  for ( ; __begin != __end; ++__begin) { 
    range_declaration = *__begin; 
    loop_statement 
  } 
} 

代码片段中的部分 auto && __range = range_expression ;,在你的示例中将变为 auto && __range = *shared_ptr_to_std_vector_of_ints() ;。函数 shared_ptr_to_std_vector_of_ints 返回一个临时对象 std::shared_ptr<std::vector<int>>,使用解引用操作符获取其中的 std::vector<int> 对象,并将其与右值引用 __range 绑定。该临时对象在完整表达式执行完成后销毁,同时对象的 use_count 减少至0,从而导致被管理的 std::vector<int> 对象被销毁。此时,__range 成为悬空引用。如果执行代码片段中的句子 auto __begin = begin_expr ;,则会尝试从 __range 中获取迭代器,这将导致未定义行为。

(上述内容中加粗部分为重点)

如果 range_expression 返回一个临时对象,则其生命周期会延长至循环结束,因为该对象被与右值引用 __range 绑定;但是要注意,range_expression 中的任何临时对象的生命周期不会得到延长。

正如你的第二个版本所示,该问题可以通过使用一个命名变量解决;或者您也可以使用 C++20 中引入的 init-statement。

for (auto temp = shared_ptr_to_std_vector_of_ints(); int i : *temp) std::cout << i << std::endl;

或者不使用额外的名称,创建一个临时变量:for (int i : std::vector<int>(*shared_ptr_to_std_vector_of_ints())) - Jarod42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接