Proper style for declaration in range-based for

不羁岁月 提交于 2019-11-30 08:47:37

First, some general advice on how to use auto that is not specific to range-for. auto&& can be problematic if the initializer is an xvalue referring to a temporary, since lifetime extension may not be applied in this case. To put it more simply, and with code:

// Pass-through identity function that doesn't construct objects
template<typename T>
T&&
id(T&& t)
{ return std::forward<T>(t); }

// Ok, lifetime extended
// T {} is a prvalue
auto&& i = T {};

T* address = &i;

// Still ok: lifetime of the object referred to by i exceed that of j
// id(whatever) is an xvalue
auto&& j = id(std::move(i));

// No other object is involved or were constructed,
// all those references are bound to the same object
assert( &j == address );

// Oops, temporary expires at semi-colon
// id(whatever) is an xvalue, again
auto&& k = id(T {});

The big clue that there's something shady going on here is that id has return type T&&. If it returned T then id(whatever) would be a prvalue, and the returned temporary would have had its lifetime extended (however that would involve a construction).


With that out of the way, when it comes to range-for though you have to remember that for(auto&& ref: init) { /* body */ } is specified to be roughly equivalent to the following (ignoring some details that don't matter here):

{
    using std::begin;
    using std::end;
    auto&& range = init;
    for(auto b = begin(range), e = end(range); b != e; ++b) {
        auto&& ref = *b;
        /* body */
    }
}

We need to ask ourselves now, what if *b is an xvalue (i.e. the iterator type has an operator* returning value_type&&, as is the case e.g. with std::move_iterator<Iterator>)? It must then refer to an object that will outlive ref, since the line auto&& ref = *b; involves no temporary. Hence it's safe. Otherwise, if *b is a prvalue (i.e. the iterator type has an operator* returning T for some object type T), then the lifetime of the temporary gets extended for the rest of the loop body. In all cases you're safe (the case where *b is an lvalue being left as an exercise to the reader).

I personally make heavy use of auto&&, with or without range-for. But I do ask myself every time whether the initializer is an xvalue or not, and if it is, what is the lifetime of what is being referred to.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!