简体   繁体   English

在基于范围的for循环中使用shared_ptr到std :: vector

[英]using shared_ptr to std::vector in range-based for loop

I wrote a c++ function that assembles some data then then returns a std::shared_ptr to a newly allocated std::vector containing the data. 我编写了一个c ++函数,它汇总了一些数据,然后将std::shared_ptr返回给包含数据的新分配的std::vector Something analogous to this: 类似于此的东西:

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;
}

I tried to iterate over the contents of the vector using a range-based for loop, but it acted as if the vector was empty. 我尝试使用基于范围的for循环迭代向量的内容,但它的作用就好像向量是空的。 After fiddling around, I found I could get it to behave as I expected by assigning the value returned from the function to a local variable, then referencing that in the loop: 摆弄后,我发现通过将函数返回的值赋给局部变量,然后在循环中引用它,我可以让它按照我的预期运行:

// 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;

That snipped prints this: 剪断打印这个:

First loop:
Second loop:
1
2
3

Why does the first version not work? 为什么第一个版本不起作用?

I'm using Xcode on macOS Sierra 10.12.6. 我在macOS Sierra 10.12.6上使用Xcode。 I believe it is using LLVM 9.0 to compile the c++ code. 我相信它正在使用LLVM 9.0来编译c ++代码。

Note that shared_ptr_to_std_vector_of_ints returns by-value, so what it returns is a temporary. 请注意, shared_ptr_to_std_vector_of_ints按值返回,因此它返回的是临时值。

The range-based for loop is equivalent to 基于范围的for循环等效于

{
  init-statement
  auto && __range = range_expression ; 
  auto __begin = begin_expr ;
  auto __end = end_expr ;
  for ( ; __begin != __end; ++__begin) { 
    range_declaration = *__begin; 
    loop_statement 
  } 
} 

The part auto && __range = range_expression ; 零件auto && __range = range_expression ; , for your example it will be auto && __range = *shared_ptr_to_std_vector_of_ints() ; ,对于你的例子,它将是auto && __range = *shared_ptr_to_std_vector_of_ints() ; . shared_ptr_to_std_vector_of_ints returns a temporary std::shared_ptr<std::vector<int>> , then dereference on it to get the std::vector<int> , then bind it to the rvalue-reference __range . shared_ptr_to_std_vector_of_ints返回一个临时的std::shared_ptr<std::vector<int>> ,然后取消引用它以获取std::vector<int> ,然后将其绑定到rvalue-reference __range The temporary std::shared_ptr<std::vector<int>> will be destroyed after the full expression, and use_count decreases to 0 so the std::vector<int> being managed is destroyed too. 在完整表达式之后,临时std::shared_ptr<std::vector<int>>将被销毁,并且use_count减少到0,因此被管理的std::vector<int>也被销毁。 Then __range becomes dangled reference. 然后__range变成__range参考。 After that eg auto __begin = begin_expr ; 之后例如auto __begin = begin_expr ; would try to get the iterator from __range , which leads to UB. 会尝试从__range获取迭代器,这会导致UB。

(emphasis mine) (强调我的)

If range_expression returns a temporary, its lifetime is extended until the end of the loop, as indicated by binding to the rvalue reference __range , but beware that the lifetime of any temporary within range_expression is not extended. 如果range_expression返回临时值,则其生命周期将延长到循环结束,如绑定到右值引用__range ,但要注意 __range 中任何临时的生命周期都不会延长。

As your 2nd version showed, the issue could be solved via using a named variable instead; 正如您的第二个版本所示,问题可以通过使用命名变量来解决; or you can also use init-statement (from C++20): 或者您也可以使用init-statement(来自C ++ 20):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM