Programing

vector :: at 대 vector :: operator []

lottogame 2020. 10. 15. 07:23
반응형

vector :: at 대 vector :: operator []


C ++ Vector at / [] operator speed 또는 :: std :: vector :: at () vs operator [] << 와 같은 유사한 질문에서도 논의되는 경계 검사로 인해 at()속도가 느리다는 것을 알고 []있습니다 . 5 ~ 10 배 더 느리게 / 빠르게! . 나는 그 방법이 무엇에 좋은지 이해하지 못합니다 .at()

이와 같은 간단한 벡터가있는 경우 : 인덱스가있는 상황에서 대신 std::vector<int> v(10);사용하여 요소에 액세스하기로 결정하고 벡터 내 경계가 있는지 확실하지 않으면 try-catch래핑해야합니다. 블록 :at()[]i

try
{
    v.at(i) = 2;
}
catch (std::out_of_range& oor)
{
    ...
}

size()색인을 직접 사용 하고 확인 하여 동일한 동작을 수행 할 수 있지만 이는 나에게 더 쉽고 편리해 보입니다.

if (i < v.size())
    v[i] = 2;

그래서 내 질문은 : vector :: operator [] 보다 vector :: at
를 사용하면 어떤 이점이 있습니까? vector :: size + vector :: operator [] 대신 vector :: at를
언제 사용해야 합니까?


vector::at()던지는 예외 는 바로 주변 코드에 의해 잡히도록 의도 된 것이 아닙니다. 주로 코드에서 버그를 잡는 데 유용합니다. 예를 들어 인덱스가 사용자 입력에서 나오기 때문에 런타임에 경계 검사가 필요한 경우 실제로 if명령문을 사용하는 것이 가장 좋습니다 . 요약하자면, vector::at()예외를 던지지 않을 의도로 코드를 디자인하십시오. 그러면 예외가 발생하고 프로그램이 중단되면 버그의 징후가됩니다. (처럼 assert())


그것은 나를 try-catch 블록으로 감싸도록 강요합니다.

아니요 (try / catch 블록은 업스트림 일 수 있음). 프로그램이 정의되지 않은 동작 영역에 들어가는 대신 예외가 발생하기를 원할 때 유용합니다.

벡터에 대한 대부분의 경계를 벗어난 액세스는 프로그래머의 실수라는 데 동의합니다 (이 경우 assert이러한 실수를 더 쉽게 찾을 수 있도록 사용해야 합니다. 대부분의 표준 라이브러리 디버그 버전은 자동으로 수행합니다). 프로그래머 실수를보고하기 위해 업스트림으로 삼킬 수있는 예외를 사용하고 싶지 않습니다 . 버그수정할 수 있기를 원합니다 .

벡터에 대한 경계를 벗어난 액세스가 정상적인 프로그램 흐름의 일부일 가능성이 낮기 때문에 (그렇다면 당신이 옳습니다 : size예외가 발생하도록하는 대신 미리 확인하십시오 ), 귀하의 진단에 동의합니다. at본질적으로 쓸모가 없습니다.


vector :: operator []보다 vector :: at를 사용하면 어떤 이점이 있습니까? vector :: size + vector :: operator [] 대신 vector :: at를 언제 사용해야합니까?

여기서 중요한 점은 예외를 사용하면 오류 처리 논리에서 코드의 정상적인 흐름을 분리 할 수 ​​있으며 단일 catch 블록이 함수 호출 내에 흩어져 있어도 무수한 throw 사이트에서 생성 된 문제를 처리 할 수 ​​있다는 것입니다. 따라서 at()한 번만 사용 하는 것이 반드시 더 쉬운 것은 아니지만 유효성을 검사 할 인덱싱이 많을 때 때때로 더 쉬워지고 일반 사례 논리의 난독 화가 줄어 듭니다.

또한 일부 코드 유형에서는 인덱스가 복잡한 방식으로 증가하고 배열을 조회하는 데 계속 사용된다는 점도 주목할 만합니다. 이러한 경우를 사용하여 올바른 검사를 확인하는 것이 훨씬 쉽습니다 at().

실제 예로서 C ++를 어휘 요소로 토큰 화하는 코드와 토큰 벡터 위로 인덱스를 이동하는 다른 코드가 있습니다. 발생한 사항에 따라 다음과 같이 다음 요소를 증분하고 확인할 수 있습니다.

if (token.at(i) == Token::Keyword_Enum)
{
    ASSERT_EQ(tokens.at(++i), Token::Idn);
    if (tokens.at(++i) == Left_Brace)
        ...
    or whatever

이런 상황 에서 입력의 끝에 부적절하게 도달 했는지 여부를 확인하는 것은 매우 어렵 습니다. 이는 발생하는 정확한 토큰에 매우 의존하기 때문입니다. 각 사용 지점에서의 명시 적 검사는 고통스럽고 사전 / 사후 증가, 사용 지점에서의 오프셋, 일부 이전 테스트의 지속적인 유효성에 대한 잘못된 추론 등으로 인해 프로그래머 오류의 여지가 훨씬 더 많습니다.


at 벡터에 대한 포인터가 있으면 더 명확해질 수 있습니다.

return pVector->at(n);
return (*pVector)[n];
return pVector->operator[](n);

성능을 제외하고 첫 번째는 더 간단하고 명확한 코드입니다.


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.)

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.


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.

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.

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().


According to this article, 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.


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.

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.

참고URL : https://stackoverflow.com/questions/9376049/vectorat-vs-vectoroperator

반응형