为什么 QList::at() 不检查索引是否存在以及 returns 一个只读值?

Why doesn't QList::at() check if index exists and also returns a read-only value?

这个问题更多的是询问,而不是实际寻求问题的解决方案。

QList::at() 不仅不检查索引是否越界而且 returns 一个 const 因此它只能在 read-only 中使用场景:

const T &QList::at(int i) const

Returns the item at index position i in the list. i must be a valid index position in the list (i.e., 0 <= i < size()).

This function is very fast (constant time).

我刚刚在尝试为列表中的元素分配新值时发现了 QList 的这些特殊实现细节,我想知道是否有这样做的理由。

不检查索引有效性

C++ STL 中,如果我们取 std::arraystd::vector(我不取 std::list,因为它根本没有 std::list::at())我们有以下内容:

std::vector::at

The function automatically checks whether n is within the bounds of valid elements in the vector, throwing an out_of_range exception if it is not

起初我认为不包括检查以确保 "This function is very fast (constant time)." 但是在查看 QList 的实现之后我不得不说即使检查被包含在一个恒定的时间(并且高速)肯定是有保障的。

检查越界需要两件事(据我所知):

那么为什么要转储索引有效性检查?性能影响真的那么大吗?

返回只读值

通过这样做,QList::at() 函数提供了一个隐藏的且(omho)不是非常有用的功能,这使得使用它和 QList::[] 的区别更加混乱。 std::vectorstd::arrayC++ STL 等效项允许使用此函数分配新值。

有“3”种方法可以从 QList 中的索引访问项目:

const T& QList::at(int) const
T& QList::operator[](int)
const T& QList::operator[](int) const

如果你看文档,你会发现最后一个很简单:

Same as at(). This function runs in constant time.

所以我们只剩下第一个 (at) 和非常量 operator[]。这是问题所在,第二个的文档告诉你 1:

If this function is called on a list that is currently being shared, it will trigger a copy of all elements. Otherwise, this function runs in constant time. If you do not want to modify the list you should use QList::at().

注:QVector也是如此:

Note that using non-const operators can cause QVector to do a deep copy.

1对于QList,这实际上只适用于Qt 5, not for Qt 4 (at least in the documentation), but for QVector it was already true for Qt 4,所以.at方法可能在所有Qt之间保持一致集装箱。

这意味着您不能直接在非常量共享 QList 或非常量 QVector 上使用 operator[],您需要执行以下操作:

QList<T> &mySharedQList = ...;
const QList<T> &myConstRef = mySharedQList;
myConstRef[0]; // Only ways not to copy the original QList

我的猜测是 .at 的目的是为您提供一种 保证 恒定访问时间的方法,无论 QListQVector 是(operator[] 不保证)。对于标准库容器,您不需要这种方法,因为非常量 operator[] 已经保证在恒定时间内 运行 (它们永远不会制作副本)。

关于索引检查,这可能是为了保持 operator[] 的行为,因为与 std::vector 不同,您可能想在任何地方使用 .at,您只需要读取数据。