根据this talk,在Qt容器上使用C ++ 11范围基础for
时存在一定的缺陷。考虑:
QList<MyStruct> list;
for(const MyStruct &item : list)
{
//...
}
根据谈话,陷阱来自隐含的分享。在引擎盖下,基于范围的for从容器中获取迭代器。但是因为容器不是const,所以interator将是非const的,这显然足以让容器分离。
当您控制容器的生命周期时,这很容易修复,只需将const引用传递给容器以强制它使用const_iterator而不是分离。
QList<MyStruct> list;
const Qlist<MyStruct> &constList = list;
for(const MyStruct &item : constList)
{
//...
}
然而,例如容器作为返回值。
QList<MyStruct> foo() { //... }
void main()
{
for(const MyStruct &item : foo())
{
}
}
这里发生了什么?容器是否仍然被复制?直觉上我会说这是为了避免这可能需要完成吗?
QList<MyStruct> foo() { //... }
main()
{
for(const MyStruct &item : const_cast<const QList<MyStruct>>(foo()))
{
}
}
我不确定。我知道它有点冗长,但是我需要这个,因为我在很大的容器上大量使用基于范围的循环,因此谈话类型与我打成了正确的字符串。
到目前为止,我使用辅助函数将容器转换为const引用,但是如果有更容易/更短的方法来实现同样的我希望听到它。
答案 0 :(得分:6)
for(auto&&item : as_const(foo()))
{
}
可能有所帮助。由于非常量迭代,返回rvalue的隐式共享对象可以隐式检测写入(和分离)。
这会给你:
template<class T>
T const as_const(T&&t){return std::forward<T>(t);}
template<class T>
T const& as_const(T&t){return t;}
允许你以const方式迭代(非常清楚)。
如果您需要参考生命周期延长才能工作,请进行2次重载:
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Timer1.Stop()
Timer1.Interval = New TimeSpan(0, 0, CInt(nudMinutes.Value), CInt(nudSeconds.Value), CInt(nudMilliseconds.Value)).TotalMilliseconds
Timer1.Start()
End Sub
但迭代const rvalues并关心它往往是一个设计错误:它们是丢弃的副本,为什么编辑它们很重要?如果你在const资格的基础上表现得非常不同,那会让你在其他地方咬人。
答案 1 :(得分:1)
Qt有一个解决方案qAsConst(请参见https://doc.qt.io/qt-5/qtglobal.html#qAsConst)。该文档说,这是Qt的C ++ 17 std :: as_const()版本。