gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 10:27:23 25 4
gpt4 key购买 nike

为什么以下代码在 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;
}

Ideone 链接: http://ideone.com/IBmhDH

最佳答案

for(:) 的范围初始化行循环不会延长除了最终临时(如果有的话)之外的任何东西的生命周期。在 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__end 行上有一个适度的谎言,所有以 __ 开头的变量都没有可见的名称。我还展示了 C++17 版本,因为我相信一个更美好的世界,以及差异在这里没关系。)

您的 exp创建一个临时对象,然后在其中返回一个引用。在那一行之后临时死掉了,所以你在其余的代码中有一个悬空引用。

修复它相对容易。要解决这个问题:
std::string const& func() const& // notice &
{
return m.find("key")->second;
}
std::string func() && // notice &&
{
return std::move(m.find("key")->second);
}

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

然后
auto&& __range=exp;

行确实在返回的副值上引用生命周期延长 string ,并且没有更多的悬空引用。

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

附录:等等, &&const&后方法? rvalue references to *this ?

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

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

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

关于c++ - 为什么在基于范围的初始化程序中使用临时对象会导致崩溃?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63767388/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com