std :: shared_ptr无法使用range

kyk*_*yku 7 c++ for-loop shared-ptr c++11

我正在尝试迭代一个范围内的临时对象for循环.看起来这个对象在循环开始执行之前被破坏了.这是符合标准的行为吗?我正在使用gcc 4.8.

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

struct Test: std::vector<int> {
  Test(): std::vector<int>{1,2,3} {
    std::cout << __PRETTY_FUNCTION__ << '\n';
  }

  ~Test() {
    std::cout << __PRETTY_FUNCTION__ << '\n';
  }
};

std::shared_ptr<Test> func() {
  return std::shared_ptr<Test>(new Test);
}

int main() {
  for (const auto &obj: *func()) {
    std::cout << obj << '\n';

  }
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

Test::Test()
Test::~Test()
21770300
0
33
0
0
0
3
Run Code Online (Sandbox Code Playgroud)

And*_*owl 14

是的,行为是合规的.

根据C++ 11标准的6.5.4/1段:

对于基于范围for的表单声明

for ( for-range-declaration : expression ) statement
Run Code Online (Sandbox Code Playgroud)

range-init等同于括号括起来的表达式

( expression )
Run Code Online (Sandbox Code Playgroud)

以及基于范围for的表单声明

for ( for-range-declaration : braced-init-list ) statement
Run Code Online (Sandbox Code Playgroud)

range-init等同于braced-init-list.在每种情况下,基于范围的for语句等同于

{
    auto && __range = range-init;
    for ( auto __begin = begin-expr,
        __end = end-expr;
        __begin != __end;
        ++__begin ) {
        for-range-declaration = *__begin;
        statement
    }
}
Run Code Online (Sandbox Code Playgroud)

在您的情况下,返回的共享指针被取消引用,它指向的对象绑定到__range引用.但是,共享指针本身不会被复制,也不会绑定到会延长其生命周期的引用.因此,它超出了范围.作为引用指向对象的最后一个共享指针,对象也被销毁.

如果Test按值返回对象,而不是返回共享指针,那么事情会有所不同:

Test func() {
  return Test();
}

int main() {
  for (const auto &obj: func()) {
    std::cout << obj << '\n';

  }
}
Run Code Online (Sandbox Code Playgroud)

这样,Test返回的临时值func()被绑定到 __range引用,并且其生命周期被延长以匹配引用的生命周期.

这是一个实例.