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

发布于 2024-11-25 07:45:10 字数 678 浏览 0 评论 0原文

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

I just found a nasty bug in my code because I captured a const reference to a string by reference. 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.

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? Moreover when looking at id under the debugger, it doesn't even look like garbage but just like a properly constructed empty string.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月亮坠入山谷 2024-12-02 07:45:10

未定义的行为意味着没有要求应该发生什么。没有要求它应该崩溃。无论您的悬空引用指向什么内存,它都没有理由不应该包含看起来像空字符串的内容,并且string的析构函数将内存留在那个状态。

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.

玩套路吗 2024-12-02 07:45:10

通过引用捕获任何内容意味着必须注意它的存活时间足够长。如果你不这样做,程序可能会正常工作,但它可能只会打电话给多米诺并点一份双份意大利辣香肠。至少,按照标准。

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. At least, according to the standard.

梦里°也失望 2024-12-02 07:45:10

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

(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. 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.

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文