Lambda:应该逐引用捕获const引用,从而产生未定义的行为

lambda: should capturing const reference by reference yield undefined behaviour?

本文关键字:引用 未定义 const Lambda      更新时间:2023-10-16

我刚刚在我的代码中发现了一个严重的错误,因为我通过引用捕获了对字符串的const引用。当lambda运行时,原始字符串对象已经消失很久了,引用的值是空的,而目的是它将包含原始字符串的值,因此出现了错误。

让我困惑的是,这并没有在运行时调用崩溃:毕竟,这不应该是未定义的行为,因为有一个悬空引用?此外,当在调试器下查看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 ]();
}

未定义的行为意味着没有要求应该发生什么。没有要求它应该崩溃。无论悬空引用指向的内存是什么,都没有理由不包含看起来像空字符串的东西,而且string的析构函数使内存处于这种状态是合理的。

通过引用捕获任何东西意味着必须注意它的存活时间足够长。如果你不这样做,程序可能会正常工作,但它可能会打电话给达美乐,点一份双层意大利辣香肠。

(正如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;
}