为什么在基于范围的初始化程序中使用临时对象会导致崩溃?

2024-02-24

为什么以下代码在 Visual Studio 和 GCC 上都会崩溃?

为了使其崩溃,需要基于范围的 for 循环、std::map、std::string 并引用字符串。如果我删除其中任何一个,它就会起作用。

#include <iostream>
#include <string>
#include <map>
using namespace std;

struct S
{
    map<string, string> m;

    S()
    {
        m["key"] = "b";
    }

    const string &func() const
    {
        return m.find("key")->second;
    }
};

int main()
{
    for (char c : S().func())
        cout << c;

    return 0;
}

创意链接:http://ideone.com/IBmhDH http://ideone.com/IBmhDH


a 的范围初始化行for(:)循环不会延长任何东西的生命周期,除了final临时的(如果有的话)。任何其他临时文件在执行之前都会被丢弃for(:)循环执行。

现在,不要绝望;这个问题有一个简单的解决方法。但首先要了解一下出了什么问题。

代码for(auto x:exp){ /* code */ }基本上扩展到:

{
  auto&& __range=exp;
  auto __it=std::begin(__range);
  auto __end=std::end(__range);
  for(; __it!=__end;++__it){
    auto x=*__it;
    /* code */
  }
}

(带着谦虚的谎言__it and __end行,以及所有以__没有可见的名字。我还展示了 C++17 版本,因为我相信有一个更美好的世界,这里的差异并不重要。)

Your exp创建一个临时对象,然后返回对其内部的引用。临时对象在该行之后消失,因此代码的其余部分有一个悬空引用。

修复它相对容易。要解决这个问题:

std::string const& func() const& // notice &
{
    return m.find("key")->second;
}
std::string func() && // notice &&
{
    return std::move(m.find("key")->second);
}

执行右值重载并返回移入的值by value当使用临时对象而不是返回对它们的引用时。

Then the

auto&& __range=exp;

行对返回的按值引用生命周期扩展string,并且不再有悬空的引用。

作为一般规则,永远不要通过引用可能是右值的参数来返回范围。


附录:等等,&& and const&方法之后?右值引用*this https://stackoverflow.com/q/8610571/1774667?

C++11 添加了右值引用。但是this或者函数的 self 参数是特殊的。要根据被调用对象的右值/左值性质选择方法的重载,您可以使用& or &&方法结束后。

这与函数参数的类型非常相似。&&在该方法声明该方法只能在非常量右值上调用之后;const&意味着应该为常量左值调用它。不完全匹配的事物遵循通常的优先规则。

当您有一个返回对象引用的方法时,请确保使用&&重载并且在这些情况下不返回引用(返回值),或者=delete方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么在基于范围的初始化程序中使用临时对象会导致崩溃? 的相关文章

随机推荐