根据这个说法,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引用,但如果有更简单/更短的方法来实现相同的我希望听到它.
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.qt.io/qt-5/qtglobal.html#qAsConst)。文档说它是 C++17 的 std::as_const() 的 Qt 版本。
| 归档时间: |
|
| 查看次数: |
6677 次 |
| 最近记录: |