【问题标题】:using shared_ptr to std::vector in range-based for loop在基于范围的 for 循环中使用 shared_ptr 到 std::vector
【发布时间】:2018-04-30 03:46:55
【问题描述】:

我编写了一个 c++ 函数,它组装一些数据,然后将 std::shared_ptr 返回到包含数据的新分配的 std::vector。类似的东西:

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++ 代码。

【问题讨论】:

  • 你真的需要shared_ptr 围绕std::vector(因为std::vector 已经管理内存)? (尤其适用于提供的用法)。

标签: c++ c++11 shared-ptr ranged-loops


【解决方案1】:

请注意,shared_ptr_to_std_vector_of_ints 按值返回,所以它返回的是临时的。

range-based for loop 等价于

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

auto &amp;&amp; __range = range_expression ; 部分,例如,auto &amp;&amp; __range = *shared_ptr_to_std_vector_of_ints() ;shared_ptr_to_std_vector_of_ints 返回一个临时的std::shared_ptr&lt;std::vector&lt;int&gt;&gt;,然后对其取消引用以获取std::vector&lt;int&gt;,然后将其绑定到右值引用__range。临时的std::shared_ptr&lt;std::vector&lt;int&gt;&gt; 将在完整表达式后被销毁,use_count 减少为 0,因此被管理的std::vector&lt;int&gt; 也被销毁。然后__range 成为悬空引用。之后例如auto __begin = begin_expr ; 会尝试从 __range 获取迭代器,这会导致 UB。

(强调我的)

如果 range_expression 返回一个临时值,则它的生命周期会延长到循环结束,如绑定到右值引用 __range 所示,但请注意 range_expression 内的任何临时值的生命周期都不会延长。

正如您的第二个版本所示,该问题可以通过使用命名变量来解决;或者您也可以使用 init-statement(来自 C++20):

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

【讨论】:

  • 或者没有额外的名字,创建一个临时的:for (int i : std::vector&lt;int&gt;(*shared_ptr_to_std_vector_of_ints()))
猜你喜欢
  • 2016-04-03
  • 2011-10-21
  • 1970-01-01
  • 1970-01-01
  • 2016-10-31
  • 2021-10-21
  • 1970-01-01
  • 2014-01-11
相关资源
最近更新 更多