在Qt中正确使用C++ 11基于范围的循环

Res*_*ion 13 c++ qt c++11

根据这个说法,for在Qt容器上使用C++ 11 range base时存在一些缺陷.考虑:

QList<MyStruct> list;

for(const MyStruct &item : list)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

根据谈话,陷阱来自隐含的分享.在引擎盖下,基于范围的for从容器中获取迭代器.但是因为容器不是const,所以interator将是非const的,这显然足以使容器分离.

当您控制容器的生命周期时,这很容易修复,只需将const引用传递给容器以强制它使用const_iterator而不是分离.

QList<MyStruct> list;
const Qlist<MyStruct> &constList = list;

for(const MyStruct &item : constList)
{
    //...
}
Run Code Online (Sandbox Code Playgroud)

然而,例如容器作为返回值.

QList<MyStruct> foo() { //... }

void main()
{
    for(const MyStruct &item : foo())
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?容器是否仍然被复制?直觉上我会说这是为了避免这可能需要做?

QList<MyStruct> foo() { //... }

main()
{ 
    for(const MyStruct &item : const_cast<const QList<MyStruct>>(foo()))
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定.我知道它有点冗长,但我需要这个,因为我在很大的容器上使用基于ranged的循环很多,所以说话的方式与我打成了正确的字符串.

到目前为止,我使用辅助函数将容器转换为const引用,但如果有更简单/更短的方法来实现相同的我希望听到它.

Yak*_*ont 8

template<class T>
std::remove_reference_t<T> const& as_const(T&&t){return t;}
Run Code Online (Sandbox Code Playgroud)

可能有帮助.由于非常量迭代,返回的隐式共享对象rvalue可以隐式检测写入(和分离).

这给你:

for(auto&&item : as_const(foo()))
{
}
Run Code Online (Sandbox Code Playgroud)

它允许你以const方式迭代(非常清楚).

如果你需要参考生命周期扩展工作,有2个重载:

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;}
Run Code Online (Sandbox Code Playgroud)

但是迭代const rvalues并关心它往往是一个设计错误:它们是丢弃的副本,为什么编辑它们才重要?如果你在const资格的基础上表现得非常不同,那会让你在其他地方咬人.

  • 较新的Qt版本将有``qAsConst``,请参阅https://doc-snapshots.qt.io/qt5-dev/qtglobal.html#qAsConst. (8认同)
  • 为了完整起见,[`std::as_const`](https://en.cppreference.com/w/cpp/utility/as_const) 是在 C++17 中引入的,它相当于 `qAsConst`。 (3认同)
  • 我也希望它用于临时对象的原因一方面是为了完整性,另一方面是因为 Qt 中的隐式共享 (COW)。基本上制作浅拷贝既快速又便宜,但是当您生成非常量迭代器时,您将执行深拷贝。Qt 类通常按值返回容器,因为它很便宜。但是如果你以非常量的方式迭代它们,你就会做深拷贝。如果您不需要它,那么进行深度复制以执行 const for-range 循环将是一种浪费(有时甚至很重要)……但也许我理解错误。:-) 无论如何,非常感谢前向技巧! (2认同)

mBa*_*dos 8

Qt 有一个实现来解决这个问题,qAsConst(参见https://doc.qt.io/qt-5/qtglobal.html#qAsConst)。文档说它是 C++17 的 std::as_const() 的 Qt 版本。