首页 > 解决方案 > 全局与局部函数对象

问题描述

我有一个返回另一个函数的函数,该函数捕获包装函数的参数。本地版本有效,但全球版本无效,我不明白为什么:

#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此外,当按值而不是按引用捕获时,全局版本也可以工作。

标签: c++c++11

解决方案


您的本地版本可能“工作”,但它也遭受与全局版本相同的问题,这是未定义的行为。在所有情况下,当您调用时,您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 拥有自己的副本,并且您不要尝试引用不再存在的东西。


推荐阅读