为什么在基于范围的初始值设定项中使用临时对象会导致崩溃?
为什么下面的代码在Visual Studio和GCC上都崩溃?
为了使它崩溃,它需要基于范围的for循环,std :: map,std :: string并引用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行中有一个适中的__it ,所有以__开始的variables都没有可见的名字,而且我正在展示C ++ 17的版本,因为我相信一个更好的世界,这里的差异并不重要。 
 你的exp创build一个临时对象,然后在其中返回一个引用。 那行后的临时死亡,所以你在代码的其余部分有一个悬而未决的参考。 
修复它是相对容易的。 要解决这个问题:
 std::string const& func() const& // notice & { return m.find("key")->second; } std::string func() && // notice && { return std::move(m.find("key")->second); } 
在使用临时对象而不是将引用返回给它们时, 通过值来实现rvalue重载和返回值的移入。
那么
 auto&& __range=exp; 
 行不会引用按值返回的string生命周期扩展,也没有更多的悬挂引用。 
作为一般规则,不要通过引用可能是右值的参数来返回范围。
 附录:等, &&和const&之后的方法?  右值引用*this ? 
  C ++ 11增加了右值引用。 但是this或者this函数的自我参数是特殊的。 要根据被调用对象的右值/左值select一个方法的重载,可以在方法结束后使用&或&& 。 
 这很像一个函数的参数types。 在方法声明该方法只在非const rvalues上被调用后  const&意味着它应该被称为常量左值。 事情不完全匹配按照通常的准则规则。 
 当你有一个返回一个对象引用的方法时,确保你用&&重载来捕获临时对象,并且在这些情况下不返回一个引用(返回一个值),或者=delete这个方法。 
 S().func() 
 这构造了一个临时对象,并且调用了一个方法,该方法返回对由临时对象拥有(间接)( std::string位于临时对象的一部分的容器中)的std::string的引用。 
 获得引用后,临时对象被破坏。 这也破坏了由临时对象拥有(间接)的std::string 。 
在那之后,引用对象的任何进一步用法变成未定义的行为。 比如遍历其内容。
这是一个非常常见的陷阱,当涉及到使用范围迭代。 你真的也因为这个而被绊倒了。