简体   繁体   English

lambda:应该按引用捕获 const 引用会产生未定义的行为吗?

[英]lambda: should capturing const reference by reference yield undefined behaviour?

I just found a nasty bug in my code because I captured a const reference to a string by reference.我刚刚在我的代码中发现了一个讨厌的错误,因为我通过引用捕获了对字符串的 const 引用。 By the time the lambda was run the original string object was already long gone and the referenced value was empty whereas the purpose was that it would contains the value of the original string, hence the bug.当 lambda 运行时,原始字符串 object 早已不复存在,并且引用的值是空的,而目的是它包含原始字符串的值,因此存在错误。

What baffles me is that this did not invoke a crash at runtime: after all, shouldn't this be undefined behaviour since afaik there is a dangling reference?让我感到困惑的是,这并没有在运行时引发崩溃:毕竟,这不应该是未定义的行为,因为 afaik 有一个悬空引用吗? Moreover when looking at id under the debugger, it doesn't even look like garbage but just like a properly constructed empty string.此外,在调试器下查看 id 时,它甚至看起来不像垃圾,而只是一个正确构造的空字符串。

Here's the test case;这是测试用例; this just prints an empty line:这只是打印一个空行:

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 ]();
}

Undefined behavior means there is no requirement what should happen.未定义的行为意味着不需要发生什么。 There is no requirement that it should crash.没有要求它应该崩溃。 Whatever memory your dangling reference points at, there's no reason it shouldn't contain something that looks like an empty string, and it's plausible that the destructor of string leaves the memory in that state.无论您的悬空参考点指向什么 memory,它都没有理由包含看起来像空字符串的东西,并且string的析构函数在 Z9ED39E2EA931586EFB3EZ9A 中离开 memory 是合理的

Capturing anything by reference means that you have to take care that it's alive long enough.通过引用捕获任何东西意味着必须注意它的生命周期足够长。 If you don't the program may just work, but it might just call Domino's and order a double pepperoni.如果您不这样做,该程序可能会正常工作,但它可能只是调用 Domino's 并订购双份意大利辣香肠。 At least, according to the standard.至少,按照标准。

(as pointed out by dascandy) The problem has little or nothing to do with the const and reference syntax, more simply it's an abdication of the responsibility to ensure the existence of everything that is passed by reference at any time it is referenced. (正如 dascandy 所指出的)问题与 const 和引用语法几乎没有关系,更简单地说,它放弃了确保在任何时候通过引用传递的所有内容都存在的责任。 The literal in the function call is strictly temporary for that call and evaporates on return, so we are accessing a temporary - a flaw often detected by the compilers - just not in this case. function 调用中的文字对于该调用是严格临时的,并且在返回时消失,因此我们正在访问一个临时的 - 编译器经常检测到的缺陷 - 只是在这种情况下不是。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM