问题描述
根据这个演讲在 Qt 容器上使用 C++11 范围基础 for
时的陷阱.考虑:
According to this talk there is a certain pitfall when using C++11 range base for
on Qt containers. Consider:
QList<MyStruct> list;
for(const MyStruct &item : list)
{
//...
}
根据谈话,陷阱来自隐式共享.在引擎盖下,基于范围的 for 从容器中获取迭代器.但是因为容器不是 const,所以 interator 将是非常量的,这显然足以让容器分离.
The pitfall, according to the talk, comes from the implicit sharing. Under the hood the ranged-based for gets the iterator from the container. But because the container is not const the interator will be non-const and that is apparently enough for the container to detach.
当您控制容器的生命周期时,这很容易解决,只需将 const 引用传递给容器以强制它使用 const_iterator 而不是分离.
When you control the lifetime of a container this is easy to fix, one just passes the const reference to the container to force it to use const_iterator and not to detach.
QList<MyStruct> list;
const Qlist<MyStruct> &constList = list;
for(const MyStruct &item : constList)
{
//...
}
但是,例如容器作为返回值.
However what about for example containers as return values.
QList<MyStruct> foo() { //... }
void main()
{
for(const MyStruct &item : foo())
{
}
}
这里发生了什么?容器还在复制吗?直觉上我会说这是为了避免可能需要这样做?
What does happen here? Is the container still copied? Intuitively I would say it is so to avoid that this might need to be done?
QList<MyStruct> foo() { //... }
main()
{
for(const MyStruct &item : const_cast<const QList<MyStruct>>(foo()))
{
}
}
我不确定.我知道它有点冗长,但我需要这个,因为我在大型容器上大量使用基于范围的 for 循环,所以谈话对我来说是正确的.
I am not sure. I know it is a bit more verbose but I need this because I use ranged based for loops heavily on huge containers a lot so the talk kind of struck the right string with me.
到目前为止,我使用辅助函数将容器转换为常量引用,但如果有更简单/更短的方法来实现相同的目标,我希望听到它.
So far I use a helper function to convert the container to the const reference but if there is a easier/shorter way to achieve the same I would like to hear it.
推荐答案
template<class T>
std::remove_reference_t<T> const& as_const(T&&t){return t;}
可能会有所帮助.由于非常量迭代,返回右值的隐式共享对象可以隐式检测写入分片(和分离).
might help. An implicitly shared object returned an rvalue can implicitly detect write-shraring (and detatch) due to non-const iteration.
这给你:
for(auto&&item : as_const(foo()))
{
}
它允许您以 const 方式(而且非常清楚)进行迭代.
which lets you iterate in a const way (and pretty clearly).
如果你需要引用生命周期延长来工作,有 2 个重载:
If you need reference lifetime extension to work, have 2 overloads:
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 右值并关心它通常是一个设计错误:它们是丢弃的副本,为什么编辑它们很重要?如果你基于 const 限定的行为非常不同,那会在其他地方咬你.
But iterating over const rvalues and caring about it is often a design error: they are throw away copies, why does it matter if you edit them? And if you behave very differently based off const qualification, that will bite you elsewhere.
这篇关于在 Qt 中正确使用 C++11 基于范围的 for 循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!