我刚刚在代码中发现了一个令人讨厌的错误,因为我通过引用捕获了对字符串的const引用。当lambda运行时,原始的字符串对象已经很久了,引用的值是空的,而目的是它将包含原始字符串的值,因此是bug。
令我感到困惑的是,这并没有在运行时调用崩溃:毕竟,这不应该是未定义的行为,因为afaik有一个悬空引用?此外,当在调试器下查看id时,它甚至看起来不像垃圾,但就像正确构造的空字符串一样。
这是测试用例;这只是打印一个空行:
typedef std::vector< std::function< void() > > functions;
void AddFunction( const std::string& id, functions& funs )
{
funs.push_back( [&id] ()
{
//the type of id is const std::string&, but there
//is no object to reference. UB?
std::cout << id << std::endl;
} );
}
int main()
{
functions funs;
AddFunction( "id", funs );
funs[ 0 ]();
}
答案 0 :(得分:4)
未定义的行为意味着没有要求会发生什么。没有要求崩溃。无论你的悬挂参考指向什么记忆,都没有理由不应该包含看起来像空字符串的东西,并且string
的析构函数在该状态下留下内存是合理的。
答案 1 :(得分:3)
通过引用捕获任何内容意味着你必须注意它的存活时间足够长。如果你不这样做,程序可能只是工作,但它可能只是调用Domino's并订购双辣椒。至少,根据标准。
答案 2 :(得分:2)
(正如dascandy所指出的)这个问题与const和引用语法几乎没有任何关系,更简单地说,它是一个职责的放弃,以确保在引用的任何时候通过引用传递的所有内容的存在。函数调用中的字面值对于该调用是严格临时的,并且在返回时会蒸发,因此我们访问临时函数 - 这是编译器经常检测到的一个缺陷 - 在这种情况下不是。
typedef std::vector<std::function<void()> > functions;
void AddFunction(const std::string& id, functions& funs) {
funs.push_back([&id] ()
{
//the type of id is const std::string&, but there
//is no object to reference. UB?
std::cout <<"id="<< id << std::endl;
});
}
int emain() {
functions funs;
std::string ida("idA");
// let idB be done by the tenporary literal below
std::string idc("idC");
AddFunction(ida, funs);
AddFunction("idB", funs);
AddFunction(idc, funs);
funs[0]();
//funs[1](); // uncomment this for (possibly) bizarre results
funs[2]();
std::cout<<"emain exit"<<std::endl;
return 0;
}
int main(int argc, char* argv[]){
int iret = emain();
return 0;
}