Rem*_*mco 6 c++ reference ranged-loops c++14
在使用ranged-for循环时,我正在获取悬空引用.考虑以下C++ 14表达式(下面的完整示例程序):
for(auto& wheel: Bike().wheels_reference())
wheel.inflate();
Run Code Online (Sandbox Code Playgroud)
它的输出是:
Wheel()
Wheel()
Bike()
~Bike() with 0 inflated wheels.
~Wheel()
~Wheel()
Wheel::inflate()
Wheel::inflate()
Run Code Online (Sandbox Code Playgroud)
显然有些事情是非常错误的.车轮超出其使用寿命,结果为0,而不是预期的2.
一个简单的解决方法是为Bikein 引入一个变量main.但是,我不控制代码main或Wheel.我只能改变结构Bike.
有没有办法通过改变来修复这个例子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;
}
Run Code Online (Sandbox Code Playgroud)
删除rvalue重载wheels_reference.
std::array<Wheel, 2>& wheels_reference() & { return wheels; }
std::array<Wheel, 2>& wheels_reference() && = delete;
Run Code Online (Sandbox Code Playgroud)
这样您就不会返回对临时成员的引用.
您对该Bike类的示例用法
for(auto& wheel: Bike().wheels_reference())
wheel.inflate();
Run Code Online (Sandbox Code Playgroud)
然后拒绝编译(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; }
Run Code Online (Sandbox Code Playgroud)
如果临时的生命周期是手动扩展的东西工作.
Bike&& bike = Bike();
for(auto& wheel: bike.wheels_reference())
wheel.inflate();
Run Code Online (Sandbox Code Playgroud)