lambda:应该通过引用捕获const引用产生未定义的行为?

时间:2011-07-21 11:17:47

标签: c++ lambda c++11 undefined-behavior

我刚刚在代码中发现了一个令人讨厌的错误,因为我通过引用捕获了对字符串的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 ]();
}

3 个答案:

答案 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;
}