我有一个函数,该函数返回另一个函数,该函数捕获包装器函数的参数。本地版本有效,但全局版本无效,我也不明白为什么:
#include <iostream>
#include <sstream>
#include <iomanip>
const auto& parseDateTimeWithFormat = [](const std::string& formatStr) {
return [&formatStr](const std::string& dateTimeStr) {
std::cout << formatStr << std::endl;
tm t = {};
std::istringstream ss(dateTimeStr);
ss >> std::get_time(&t, formatStr.c_str());
const int timestamp = (int)mktime(&t);
return timestamp;
};
};
const auto& parseDateTime1 = parseDateTimeWithFormat("%Y-%m-%dT%H:%M:%SZ");
int main(int argc, const char* argv[]) {
int ts1 = parseDateTime1("2018-10-08T10:09:08Z");
std::cout << ts1 << std::endl;
const auto& parseDateTime2 = parseDateTimeWithFormat("%Y-%m-%dT%H:%M:%SZ");
int ts2 = parseDateTime2("2018-10-08T10:09:08Z");
std::cout << ts2 << std::endl;
return 0;
}
输出:
(empty string)
-1
%Y-%m-%dT%H:%M:%SZ
1538989748
此外,当按值而不是按引用捕获formatStr
时,全局版本也适用。
答案 0 :(得分:2)
您的本地版本可能“起作用”,但它也遭受与全局版本相同的问题,这是未定义的行为。在所有情况下,当您调用parseDateTimeWithFormat
时,都将给出字符串文字。由于这不是std::string
,因此会为您创建一个临时的。该字符串就是您在
return [&formatStr](const std::string& dateTimeStr) {
std::cout << formatStr << std::endl;
tm t = {};
std::istringstream ss(dateTimeStr);
ss >> std::get_time(&t, formatStr.c_str());
const int timestamp = (int)mktime(&t);
return timestamp;
};
然后返回lambda。不幸的是,一旦表达式结束,您调用parseDateTimeWithFormat
的地方即被破坏,并且留下了对formatStr
的悬挂引用。就像您发现的那样,解决方法是按值捕获,以便lambda具有自己的副本,并且您不会尝试引用不再存在的内容。