1

Consider the following piece of C++11 code which is the smallest reproducer I could come up with:

#include <iostream>
#include <boost/range/adaptor/transformed.hpp>

std::vector<uint32_t> myTransform(const std::vector<uint32_t>& iVector) {
  return iVector;
}

int main() {
  const std::vector<std::vector<uint32_t>> theInput{{1, 2}};
  const auto myRange = theInput | boost::adaptors::transformed(myTransform);

  for (auto it = boost::begin(myRange); it != boost::end(myRange); ++it) {
    for (auto it2 = boost::begin(*it); it2 != boost::end(*it); ++it2) {
      std::cout << *it2 << std::endl;
    }
  }
}

I expected it to print the following output:

1
2

... but instead it prints (cf http://cpp.sh/8yivt):

0
0

However, if I change myTransform to return a reference like this:

const std::vector<uint32_t>& myTransform(const std::vector<uint32_t>& iVector) {
  return iVector;
}

... then I get the expected output (cf http://cpp.sh/5brvl).

I couldn't find any explanation for this behavior from the Boost.Range documentation. Is my code incorrect ? Are my expectations incorrect ? Is it a bug/known limitation in Boost.Range ?

The aim of this question is first and foremost to understand why this behaves in an unexpected way, and only incidentally to find a solution.

koral
  • 442
  • 3
  • 11
  • 2
    Try `auto vec = *it` and `for (auto it2 = boost::begin(vec); it2 != boost::end(vec); ++it2) { ... }`, or try a range based for loop: `for (uint32_t x : *it) { ... }`. I suspect that `*it` returns a vector by value, which is promptly destroyed after the call to `boost::begin`, meaning that `it2` dangles. – Justin Aug 21 '19 at 20:04
  • Using `auto vec = *it` prints the expected output `1 2` (cf http://cpp.sh/5hw3t). – koral Aug 21 '19 at 20:31
  • I also suspect `*it` is promptly destroyed, the point of the question is to understand why, if this is indeed the case. – koral Aug 28 '19 at 19:04
  • Look up "temporary lifetime" or "lifetime of temporaries". In short, temporaries only live until the end of the statement (generally the next `;`). Objects are automatically destroyed at the end of their lifetime. Therefore, the temporary is destroyed after the initialization of `it2`, but before any iteration actually happens. – Justin Aug 28 '19 at 19:53

0 Answers0