c++loopsc++11rvalueboost-foreach

Iterating through an rvalue container


Is the following code causing undefined behavior?

std::map<int, vector<int>> foo()
{
return ...
}

BOOST_FOREACH(const int& i, foo()[42])
{
std::cout << i << std::endl;
}

If undefined, What is the good way to fix it? What if I use c++11 range-for loop instead of BOOST_FOREACH?


Solution

  • This is, unfortunately, most probably undefined behavior.

    The problem is that you have two levels here:

    1. std::map<...> is an r-value, its lifetime will be expanded until the end of the full-expression
    2. std::vector<int>& is an l-value reference (into an object), its lifetime is that of the object.

    The problem arises because the code (roughly) expands to something like:

    // from
    for (<init>: <expr>) {
        <body>
    }
    
    // to
    auto&& __container = <expr>;
    for (auto __it = begin(container), __e = end(container); __it != __e; ++__it)
    {
        <init> = *__it;
        <body>
    }
    

    The issue here is in the initialization of __container:

    auto&& __container = foo()[42];
    

    If it where just foo(), this would work, because the lifetime of std::map<...> would be extended to match that of __container, however in this case we get:

    // non-standard gcc extension, very handy to model temporaries:
    std::vector<int>& __container = { std::map<...> m = foo(); m[42] };
    

    And thus __container ends up pointing into the nether.