C++ C++;11迭代器和返回的std::unique\u ptr的范围

C++ C++;11迭代器和返回的std::unique\u ptr的范围,c++,c++11,scope,iterator,ranged-loops,c++14,C++,C++11,Scope,Iterator,Ranged Loops,C++14,问题 据我所知,当函数将std::unique_ptr返回到右值时,它的生存期应该包含使用该右值的语句。但是使用gcc 6.4.1编译时,在函数crashing\u version()中的C++11 foreach语句开始之前,来自Foo::iterator()的返回值超出范围。如下面的输出所示,析构函数是在计算包含表达式之后调用的。这是gcc中的错误还是糟糕的编程实践 用例 该模式的目标是在不公开私有向量的情况下使迭代可用。这似乎需要一些对象,比如Foo::Iterator,因为有两个单独的列

问题

据我所知,当函数将
std::unique_ptr
返回到右值时,它的生存期应该包含使用该右值的语句。但是使用gcc 6.4.1编译时,在函数
crashing\u version()
中的C++11 foreach语句开始之前,来自
Foo::iterator()的返回值超出范围。如下面的输出所示,析构函数是在计算包含表达式之后调用的。这是gcc中的错误还是糟糕的编程实践

用例

该模式的目标是在不公开私有向量的情况下使迭代可用。这似乎需要一些对象,比如
Foo::Iterator
,因为有两个单独的列表需要迭代

#包括
#包括
#包括
类Foo{
/*目标:允许迭代而不暴露向量对象。*/
std::vector_list0;
std::vector_list1;
公众:
类迭代器{
内部列表id;
富和富;
公众:
迭代器(int-list\u-id,Foo&Foo):\u-list\u-id(list\u-id),\u-Foo(Foo){
~Iterator(){

std::cout您的代码表现出未定义的行为。gcc、msvc和clang的行为都是相同的;迭代器的析构函数在输出任何内容之前运行

在本例中,基于范围的for循环可以被视为缓存函数调用的一种方便方法,因此您的代码等价于此*([stmt.range]):

auto&&range=*foo.iterator(1);
对于(自动开始=范围.开始(),uu结束=范围.结束();u开始!=u结束;++u开始){
int i=*\u开始;
std::coutA
for(range\u声明:range\u表达式)
表达式等价于(in和):

,以
开头的变量仅作为expension存在

我们替换为:

for (int i : *evens)                                                               
    std::cout << i << "\n";                                                        
现在我们做到了:

for (int i : range_ptr(evens))                                                               
    std::cout << i << "\n";                                                        

不幸的是,由于这种行为的可观察性,在范围表达式内延长临时变量的寿命将是一个突破性的变化。这使得它不如第一印象中的好主意。我不完全理解为什么
范围\u ptr\t
保持在范围内。是因为
范围获得了
range\u ptr\u t
的实际实例,因为其类型直接与兼容(隐藏)迭代器规范?@ByronHawkins
\uuuu range
捕获
range\u ptr\t
,因为
range\u表达式
是一个类型为
range\u ptr\t
的PR值,它准确捕获
range\u表达式
计算为的内容,并遵循
自动&
规则(在本例中,这使其成为绑定到实例化为临时的prvalue的右值引用,该prvalue随后被引用生存期延长)。在您的情况下,它绑定到一元
*
的返回值,该返回值来自
唯一的\u ptr
,这不是临时的,因此它的生存期不会延长。现在,
范围\u ptr\t
用作
范围\u表达式
,因为它有一个
开始
结束
返回迭代器。@ByronHawkins and use“迭代器”指的是概念或“范围”“Iterator是一个定义在C++中的概念,不要重用它。”拜伦生命不止是内存,它是副作用、各种资源、锁等等。它是确定性清理。它意味着你必须跟踪谁拥有什么东西,智能容器/指针消除了一些开销。
for (int i : *evens)                                                               
    std::cout << i << "\n";                                                        
{
  auto && __range = *evens;
  for (
    auto __begin = begin_expr, __end = end_expr;
    __begin != __end;
    ++__begin)
  {
    int i = *__begin;
    std::cout << i << "\n";                                                        
  }
} 
template<class Ptr>
struct range_ptr_t {
  Ptr p;
  auto begin() const {
    using std::begin;
    return begin(*p);
  }
  auto end() const {
    using std::end;
    return end(*p);
  }
};
template<class Ptr>
range_ptr_t<std::decay_t<Ptr>> range_ptr( Ptr&& ptr ) {
  return {std::forward<Ptr>(ptr)};
}
for (int i : range_ptr(evens))                                                               
    std::cout << i << "\n";                                                        
std::unique_ptr<std::vector<int>> foo() {
  return std::make_unique<std::vector<int>>( std::vector<int>{ 1, 2, 3} );
}


int main() {
  for (int x : range_ptr(foo())) {
    std::cout << x << '\n';
  }
}