C++ vector::at 与 vector::operator[]
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9376049/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
vector::at vs. vector::operator[]
提问by LihO
I know that at()
is slower than []
because of its boundary checking, which is also discussed in similar questions like C++ Vector at/[] operator speedor ::std::vector::at() vs operator[] << surprising results!! 5 to 10 times slower/faster!. I just don't understand what the at()
method is good for.
我知道这at()
比[]
因为它的边界检查慢,这也在类似的问题中讨论过,比如C++ Vector at/[] operator speed或::std::vector::at() vs operator[] << 令人惊讶的结果!!慢/快 5 到 10 倍!. 我只是不明白这种at()
方法有什么好处。
If I have a simple vector like this one: std::vector<int> v(10);
and I decide to access its elements by using at()
instead of []
in situation when I have a index i
and I'm not sure if its in vectors bounds, it forces me to wrap it with try-catch block:
如果我有一个像这样的简单向量:std::vector<int> v(10);
并且我决定通过使用at()
而不是[]
在我有索引的情况下访问它的元素i
并且我不确定它是否在向量范围内,它迫使我用 try-catch 包装它块:
try
{
v.at(i) = 2;
}
catch (std::out_of_range& oor)
{
...
}
although I'm able to do the get the same behaviour by using size()
and checking the index on my own, which seems easier and much convenient for me:
尽管我可以通过自己使用size()
和检查索引来获得相同的行为,但这对我来说似乎更容易和方便:
if (i < v.size())
v[i] = 2;
So my question is:
What are advantages of using vector::atover vector::operator[]?
When should I use vector::atrather than vector::size+ vector::operator[]?
所以我的问题是:
使用vector::at比使用vector::operator[] 有什么优势?
我什么时候应该使用vector::at而不是vector::size+ vector::operator[]?
采纳答案by pmdj
I'd say the exceptions that vector::at()
throws aren't really intended to be caught by the immediately surrounding code. They are mainly useful for catching bugs in your code. If you need to bounds-check at runtime because e.g. the index comes from user input, you're indeed best off with an if
statement. So in summary, design your code with the intention that vector::at()
will never throw an exception, so that if it does, and your program aborts, it's a sign of a bug. (just like an assert()
)
我会说vector::at()
抛出的异常并不是真的要被周围的代码捕获。它们主要用于捕获代码中的错误。如果您需要在运行时进行边界检查,因为例如索引来自用户输入,那么您确实最好使用if
语句。因此,总而言之,设计您的代码时要考虑到vector::at()
永远不会抛出异常,因此如果抛出异常并且您的程序中止,那就是一个错误的迹象。(就像一个assert()
)
回答by Alexandre C.
it forces me to wrap it with try-catch block
它迫使我用 try-catch 块包装它
No it doesn't (the try/catch block can be upstream). It is useful when you want an exception to be thrown rather than your program to enter undefined behavior realm.
不,它没有(try/catch 块可以在上游)。当您希望抛出异常而不是您的程序进入未定义的行为领域时,它很有用。
I agree that most out of bounds accesses to vectors are a programmer's mistake (in which case you ought to use assert
to locate those mistakes more easily; most debug versions of standard libraries do this automatically for you). You do not want to use exceptions that can be swallowed upstream to report programmer mistakes: you want to be able to fix the bug.
我同意对向量的大多数越界访问是程序员的错误(在这种情况下,您应该使用assert
更轻松地定位这些错误;标准库的大多数调试版本会自动为您执行此操作)。您不想使用可以被上游吞噬的异常来报告程序员错误:您希望能够修复错误。
Since it is unlikely that an out of bounds access to a vector is part of the normal program flow (in the case it is, you're right: check beforehand with size
instead of letting the exception bubble up), I agree with your diagnostic: at
is essentially useless.
由于对向量的越界访问不太可能是正常程序流程的一部分(在这种情况下,您是对的:事先检查size
而不是让异常冒泡),我同意您的诊断:at
基本没用。
回答by Tony Delroy
What are advantages of using vector::at over vector::operator[] ? When should I use vector::at rather than vector::size + vector::operator[] ?
使用 vector::at 比使用 vector::operator[] 有什么优势?我什么时候应该使用 vector::at 而不是 vector::size + vector::operator[] ?
The important point here is that exceptions allow separation of the normal flow of code from the error handling logic, and a single catch block can handle problems generated from any of myriad throw sites, even if scattered deep within function calls. So, it's not that at()
is necessarily easier for a single use, but that sometimes it becomes easier - and less obfuscating of normal-case logic - when you have a lot of indexing to validate.
这里的重点是异常允许将正常的代码流与错误处理逻辑分离,并且单个 catch 块可以处理由无数抛出站点中的任何一个产生的问题,即使它们分散在函数调用的深处。因此,at()
单次使用并不一定更容易,但有时它会变得更容易 - 并且减少对正常情况逻辑的混淆 - 当您有很多索引要验证时。
It's also noteworthy that in some types of code, an index is being incremented in complex ways, and continually used to look up an array. In such cases, it's much easier to ensure correct checks using at()
.
同样值得注意的是,在某些类型的代码中,索引以复杂的方式递增,并不断用于查找数组。在这种情况下,使用at()
.
As a real-world example, I have code that tokenises C++ into lexical elements, then other code that moves an index over the vector of tokens. Depending on what's encountered, I may wish to increment and check the next element, as in:
作为一个真实的例子,我有将 C++ 标记为词法元素的代码,然后是将索引移动到标记向量上的其他代码。根据遇到的情况,我可能希望增加并检查下一个元素,如下所示:
if (token.at(i) == Token::Keyword_Enum)
{
ASSERT_EQ(tokens.at(++i), Token::Idn);
if (tokens.at(++i) == Left_Brace)
...
or whatever
In this kind of situation, it's very hard to check whether you've inappropriatelyreached the end of the input because that's very dependent on the exact tokens encountered. Explicit checking at each point of use is painful, and there's much more room for programmer error as pre/post increments, offsets at the point of use, flawed reasoning about the continued validity of some earlier test etc. kick in.
在这种情况下,很难检查您是否不恰当地到达了输入的末尾,因为这非常依赖于遇到的确切标记。在每个使用点进行显式检查是痛苦的,并且随着前/后增量、使用点的偏移、关于某些早期测试的持续有效性的错误推理等,程序员错误的空间更大。
回答by Brangdon
at
can be clearer if you have a pointer to the vector:
at
如果你有一个指向向量的指针会更清楚:
return pVector->at(n);
return (*pVector)[n];
return pVector->operator[](n);
Performance aside, the first of these is the simpler and clearer code.
撇开性能不谈,首先是更简单、更清晰的代码。
回答by James Kanze
First, whether at()
or operator[]
is slower is not specified. When
there's no bounds error, I'd expect them to be about the same speed, at
least in debugging builds. The difference is that at()
specifies
exactly what will happen in there is a bounds error (an exception),
where as in the case of operator[]
, it is undefined behavior—a
crash in all of the systems I use (g++ and VC++), at least when the
normal debugging flags are used. (Another difference is that once I'm
sure of my code, I can get a substantial speed increase for operator[]
by turning the debugging off. If the performance requires it—I
wouldn't do it unless it were necessary.)
首先,是否at()
还是operator[]
较慢没有规定。当没有边界错误时,我希望它们的速度大致相同,至少在调试版本中是这样。不同之处在于它at()
确切地指定了在边界错误(异常)中会发生什么,在这种情况下operator[]
,它是未定义的行为——在我使用的所有系统(g++ 和 VC++)中崩溃,至少当使用正常的调试标志。(另一个区别是,一旦我确定我的代码,我可以operator[]
通过关闭调试来获得显着的速度提升。如果性能需要它 - 除非必要,否则我不会这样做。)
In practice, at()
is rarely appropriate. If the context is such that
you know the index may be invalid, you probably want the explicit test
(e.g. to return a default value or something), and if you know that it
can't be invalid, you want to abort (and if you don't know whether it
can be invalid or not, I'd suggest that you specify your function's
interface more precisely). There are a few exceptions, however, where
the invalid index may result from parsing user data, and the error
should cause an abort of the entire request (but not bring the server
down); in such cases, an exception is appropriate, and at()
will do
that for you.
在实践中,at()
很少适用。如果上下文使您知道索引可能无效,您可能需要显式测试(例如返回默认值或其他内容),并且如果您知道它不能无效,您想中止(如果你不知道它是否可以无效,我建议你更精确地指定你的函数接口)。但是,有一些例外,其中无效索引可能是由于解析用户数据而导致的,并且该错误应该导致整个请求中止(但不会使服务器停机);在这种情况下,例外是适当的,并且at()
会为您做到这一点。
回答by ltjax
The whole point of using exceptions is that your error handling code can be further away.
使用异常的全部意义在于您的错误处理代码可以更远。
In this specific case, user input is indeed a good example. Imagine you want to semantically analyze an XML data-structure which uses indices to refer to some kind of resource you internally store in a std::vector
. Now the XML tree is a tree, so your probably want to use recursion to analyze it. Deep down, in the recursion, there might be an access violation by the writer of the XML file. In that case, you usually want to bump out of all the levels of recursion and just reject the whole file (or any kind of "coarser" structure). This is where at comes in handy. You can just write the analysis code as-if the file was valid. The library code will take care of the error detection and you can just catch the error on the coarse level.
在这种特定情况下,用户输入确实是一个很好的例子。假设您想从语义上分析一个 XML 数据结构,该结构使用索引来引用您内部存储在std::vector
. 现在 XML 树是一棵树,所以您可能想使用递归来分析它。在深层,在递归中,XML 文件的编写者可能存在访问冲突。在这种情况下,您通常希望跳出所有级别的递归并拒绝整个文件(或任何类型的“粗略”结构)。这就是 at 派上用场的地方。您可以像文件有效一样编写分析代码。库代码将负责错误检测,您可以在粗略级别上捕获错误。
Also, other containers, like std::map
, also have std::map::at
which has slightly different semantics than std::map::operator[]
: at can be used on a const map, while operator[]
cannot. Now if you wanted to write container agnostic code, like something that could deal with either const std::vector<T>&
or const std::map<std::size_t, T>&
, ContainerType::at
would be your weapon of choice.
此外,其他容器,如std::map
,也具有std::map::at
与std::map::operator[]
:at略有不同的语义,可以在 const 映射上使用,而operator[]
不能。现在,如果您想编写与容器无关的代码,例如可以处理const std::vector<T>&
或 的代码const std::map<std::size_t, T>&
,ContainerType::at
将是您选择的武器。
However, all these cases usually appear when handling some kind of unvalidated data-input. If you are sure about your valid range, as you usually should be, you can usually use operator[]
, but better yet, iterators with begin()
and end()
.
但是,在处理某种未经验证的数据输入时,通常会出现所有这些情况。如果你确定你的有效范围,你通常应该是,你通常可以使用operator[]
,但更好的是,迭代器begin()
和end()
。
回答by ahj
According to thisarticle, performance aside, it doesn't make any difference to use at
or operator[]
, only if the access is guaranteed to be within the size of the vector. Otherwise, if access is just based on the capacity of the vector it is safer to use at
.
根据这篇文章,抛开性能不谈,使用at
or没有任何区别operator[]
,仅当访问保证在向量的大小范围内时。否则,如果访问仅基于向量的容量,则使用at
.
回答by Shital Shah
Note:It appears some new folks are downvoting this answer without having courtesy of telling what is wrong. Below answer is correct and can be verified here.
注意:似乎有些新人在没有礼貌地说出错误的情况下对这个答案投反对票。下面的答案是正确的,可以在这里验证。
There is really only one difference: at
does bounds checking while operator[]
doesn't. This applies to debug builds as well as release builds and this is very well specified by the standards. It's that simple.
实际上只有一个区别:at
是否进行边界检查operator[]
。这适用于调试版本和发布版本,并且这在标准中有很好的规定。就这么简单。
This makes at
a slower method but it's also really bad advice to not to use at
. You have to look at absolute numbers, not relative numbers. I can safely bet that most of your code is doing fat more expensive operations than at
. Personally, I try to use at
because I don't want a nasty bug to create undefined behavior and sneak in to production.
这是at
一种较慢的方法,但不使用at
. 你必须看绝对数字,而不是相对数字。我可以肯定地打赌,您的大部分代码都在执行比at
. 就我个人而言,我尝试使用at
是因为我不希望一个讨厌的错误创建未定义的行为并潜入生产环境。