7

我正在尝试遍历 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';

  }
}

结果如下:

Test::Test()
Test::~Test()
21770300
0
33
0
0
0
3
4

1 回答 1

14

Yes, the behavior is compliant.

Per paragraph 6.5.4/1 of the C++11 Standard:

For a range-based for statement of the form

for ( for-range-declaration : expression ) statement

let range-init be equivalent to the expression surrounded by parentheses

( expression )

and for a range-based for statement of the form

for ( for-range-declaration : braced-init-list ) statement

let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to

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

In your case, the returned shared pointer is dereferenced, and the object it points to is bound to the __range reference. However, the shared pointer itself is not copied, nor is it bound to a reference that would prolong its lifetime. Therefore, it goes out of scope. Being the last shared pointer referencing the pointed object, the object gets destroyed too.

Things would have been different if you had returned your Test object by value, rather than returning a shared pointer:

Test func() {
  return Test();
}

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

  }
}

This way, the Test temporary returned by func() is bound to the __range reference, and its lifetime is prolonged to match the lifetime of the reference.

Here is a live example.

于 2013-04-26T16:10:48.837 回答