在使用ranged-for循环时,我正在获取悬空引用.考虑以下C 14表达式(下面的完整示例程序):
for(auto& wheel: Bike().wheels_reference()) wheel.inflate();
它的输出是:
Wheel() Wheel() Bike() ~Bike() with 0 inflated wheels. ~Wheel() ~Wheel() Wheel::inflate() Wheel::inflate()
显然有些事情是非常错误的.车轮超出其使用寿命,结果为0,而不是预期的2.
一个简单的解决方法是在主要部分为Bike引入一个变量.但是,我不控制main或Wheel中的代码.我只能更改struct Bike.
有没有办法通过改变自行车来修复这个例子?
一个成功的解决方案解决方案要么在编译时失败,要么计算2个充气轮胎并且不会触及超出其生命周期的任何物体.
附录:编译就绪源
#include <cstdlib> #include <iostream> #include <array> #include <algorithm> using std::cout; using std::endl; struct Wheel { Wheel() { cout << " Wheel()" << endl; } ~Wheel() { cout << "~Wheel()" << endl; } void inflate() { inflated = true; cout << " Wheel::inflate()" << endl; } bool inflated = false; }; struct Bike { Bike() { cout << " Bike()" << endl; } ~Bike() { cout << "~Bike() with " << std::count_if(wheels.begin(),wheels.end(),[](auto& w) { return w.inflated; }) << " inflated wheels." << endl; } std::array<Wheel,2>& wheels_reference() { return wheels; } std::array<Wheel,2> wheels{Wheel(),Wheel()}; }; int main() { for(auto& wheel: Bike().wheels_reference()) wheel.inflate(); return EXIT_SUCCESS; }
解决方法
删除wheels_reference的rvalue重载.
std::array<Wheel,2>& wheels_reference() & { return wheels; } std::array<Wheel,2>& wheels_reference() && = delete;
这样您就不会返回对临时成员的引用.
您对Bike类的示例用法
for(auto& wheel: Bike().wheels_reference()) wheel.inflate();
然后拒绝编译(clang 3.4输出):
test.cpp:31:29: error: call to deleted member function 'wheels_reference' for(auto& wheel: Bike().wheels_reference()) ~~~~~~~^~~~~~~~~~~~~~~~ test.cpp:24:27: note: candidate function has been explicitly deleted std::array<Wheel,2>& wheels_reference() && = delete; ^ test.cpp:23:27: note: candidate function not viable: no known conversion from 'Bike' to 'Bike' for object argument std::array<Wheel,2>& wheels_reference() & { return wheels; }
如果临时的生命周期是手动扩展的东西工作.
Bike&& bike = Bike(); for(auto& wheel: bike.wheels_reference()) wheel.inflate();