Home > Net >  Returning objects constructed in lambda in transform
Returning objects constructed in lambda in transform

Time:10-04

The following function does something different than I want, which is to return the matches. If I call it on vector<string>{"a b", "cd ef"}, the output is

cd 
cd ef

instead of

a b
cd ef

Why?

#include <regex>
using namespace std;

void f(const vector<string>& v) {
  vector<smatch> P{};
  transform(begin(v), end(), back_inserter(P), [](auto s){
    auto m = *new smatch;
    regex_match(s, m, regex{"(\\S*) (\\S*) ?(.*)"});
    return m;
  });
  for (auto s: P) cout << s[0] << endl; // debug output
}

It's the same if I try without new: smatch m{};. Which I believe I shouldn't do, because then the smatch is allocated on the stack and invalidated when the lambda function returns. (I even tried smatch m;, but that should create an uninitialized variable. Oddly, it works with no runtime error, giving the same wrong result.) And the following doesn't even compile, giving an error I don't understand:

#include <regex>
using namespace std;

void f(const vector<string>& v) {
  vector<smatch> P{};
  transform(begin(v), end(), back_inserter(P), [](auto s){
    auto m = new smatch;
    regex_match(s, m, regex{"(\\S*) (\\S*) ?(.*)"});
    cout << (*m)[0] << endl;
    return m;
  });
  for (auto s: P) cout << (*s)[0] << endl;
}

CodePudding user response:

For std::match_results:

Because std::match_results holds std::sub_matches, each of which is a pair of iterators into the original character sequence that was matched, it's undefined behavior to examine std::match_results if the original character sequence was destroyed or iterators to it were invalidated for other reasons.

The parameter s of the lambda is passed by-value, it'll be destroyed when get out of the lambda. You can change it to pass-by-reference:

void f(const vector<string>& v) {
  vector<smatch> P;
  transform(begin(v), end(v), back_inserter(P), [](auto& s){
    //                                                 ^
    smatch m;
    regex_match(s, m, regex{"(\\S*) (\\S*) ?(.*)"});
    return m;
  });
  for (auto s: P) cout << s[0] << endl; // debug output
}
  • Related