为什么 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::array
或 std::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
的实现之后我不得不说即使检查被包含在一个恒定的时间(并且高速)肯定是有保障的。
检查越界需要两件事(据我所知):
- 检查给定索引是否小于 0 - 这是一个恒定时间检查(
O(1)
如果我们使用一些古怪的符号)。显然我们不能有负索引(我们可以在 Python
但它有另一个含义 ;))
检查给定索引是否 < QList::size()
- 由于 QList::size()
的实现方式是:
,此处也存在常数时间
inline int size() const Q_DECL_NOTHROW { return d->end - d->begin; }
这又是 O(1)
(如果我没记错的话),因为两个值都存储在 QList::d
参数中,该参数是指向
的指针
struct Data {
QtPrivate::RefCount ref;
int alloc, begin, end;
void *array[1];
};
所以访问它们并计算它们的差异不会对性能造成太大影响(显然它有一些轻微的影响,因为它引入了一些访问和算术操作以及由于 [ 内部的跳转而备份和恢复堆栈=26=]函数).
那么为什么要转储索引有效性检查?性能影响真的那么大吗?
返回只读值
通过这样做,QList::at()
函数提供了一个隐藏的且(omho)不是非常有用的功能,这使得使用它和 QList::[]
的区别更加混乱。 std::vector
和 std::array
的 C++ 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
的目的是为您提供一种 保证 恒定访问时间的方法,无论 QList
或QVector
是(operator[]
不保证)。对于标准库容器,您不需要这种方法,因为非常量 operator[]
已经保证在恒定时间内 运行 (它们永远不会制作副本)。
关于索引检查,这可能是为了保持 operator[]
的行为,因为与 std::vector
不同,您可能想在任何地方使用 .at
,您只需要读取数据。
这个问题更多的是询问,而不是实际寻求问题的解决方案。
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::array
或 std::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
的实现之后我不得不说即使检查被包含在一个恒定的时间(并且高速)肯定是有保障的。
检查越界需要两件事(据我所知):
- 检查给定索引是否小于 0 - 这是一个恒定时间检查(
O(1)
如果我们使用一些古怪的符号)。显然我们不能有负索引(我们可以在Python
但它有另一个含义 ;)) 检查给定索引是否 <
,此处也存在常数时间QList::size()
- 由于QList::size()
的实现方式是:inline int size() const Q_DECL_NOTHROW { return d->end - d->begin; }
这又是
的指针O(1)
(如果我没记错的话),因为两个值都存储在QList::d
参数中,该参数是指向struct Data { QtPrivate::RefCount ref; int alloc, begin, end; void *array[1]; };
所以访问它们并计算它们的差异不会对性能造成太大影响(显然它有一些轻微的影响,因为它引入了一些访问和算术操作以及由于 [ 内部的跳转而备份和恢复堆栈=26=]函数).
那么为什么要转储索引有效性检查?性能影响真的那么大吗?
返回只读值
通过这样做,QList::at()
函数提供了一个隐藏的且(omho)不是非常有用的功能,这使得使用它和 QList::[]
的区别更加混乱。 std::vector
和 std::array
的 C++ 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
的目的是为您提供一种 保证 恒定访问时间的方法,无论 QList
或QVector
是(operator[]
不保证)。对于标准库容器,您不需要这种方法,因为非常量 operator[]
已经保证在恒定时间内 运行 (它们永远不会制作副本)。
关于索引检查,这可能是为了保持 operator[]
的行为,因为与 std::vector
不同,您可能想在任何地方使用 .at
,您只需要读取数据。