在Qt

时间:2016-03-05 06:46:26

标签: c++ qt c++11

根据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引用,但是如果有更容易/更短的方法来实现同样的我希望听到它。

2 个答案:

答案 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()版本。