인덱스 변수 유형 선택


11

Integer 타입은 대부분 인덱스 변수를 나타냅니다. 하지만 어떤 상황에서는

std::vector<int> vec;
....

for(int i = 0; i < vec.size(); ++i)
....

이로 인해 컴파일러는 부호있는 / 부호없는 변수의 혼합 사용에 대한 경고를 발생시킵니다. 나는 인덱스 등의 변수를 만들 경우 for( size_t i = 0; i < vec.size(); i++ ), (또는을 unsigned int)이 문제를 정렬합니다.

Windows 유형을 사용하는 것이 더 구체적 일 때, 대부분의 Windows API는 DWORD (부호없는 long으로 typedef를 처리)를 처리합니다.

따라서 비슷한 반복을 사용하면 동일한 경고가 다시 발생합니다. 이제 다시 작성하면

DWORD dwCount;
....

for(DWORD i = 0; i < dwCount; ++i)
....

나는 이것이 조금 이상하다고 생각한다. 인식에 문제가있을 수 있습니다.

인덱스 변수에 범위 문제가 발생할 수있는 것을 피하기 위해 동일한 유형의 인덱스 변수를 사용해야한다는 것에 동의합니다. 예를 들어 우리가 사용하는 경우

_int64 i64Count; // 
....

for(_int64 i = 0; i < i64Count; ++i)
....

그러나 DWORD 또는 부호없는 정수의 경우 다시 작성하는 데 문제가 있습니까?

for(int i = 0; (size_t)i < vec.size(); ++i)

대부분의 사람들이 비슷한 문제로 어떻게 일하고 있습니까?


4
왜 부호있는 정수를 사용하여 색인을 나타내겠습니까? 정수 벡터를 사용하여 문자열을 저장하는 것과 같습니다.
Šimon Tóth

3
@Let_Me_Be : 경계 조건을 쉽게 테스트 할 수 있기 때문입니다. 예를 들어 카운트가 0으로 내려 가면 루프 본문을 실행하기 전에 테스트 미만이 부호없는 값으로 작동 할 수 없습니다. 마찬가지로 최대 개수까지 작동하지 않습니다. 물론이 경우 부호있는 정수도 작동하지 않습니다 (왜냐하면 큰 값을 나타낼 수 없기 때문입니다).
트릴

"이로 인해 컴파일러는 부호있는 / 서명되지 않은 변수의 혼합 사용에 대한 경고를 발생시킵니다." 그것은 당신이 싸워야 할 두 가지 문제 중 하나 일뿐 입니다. 많은 경우 std::size_t에 int (또는 심지어는 long)보다 높은 순위입니다. 벡터의 크기가을 (를) 초과하면 std::numeric_limits<int>::max()int를 사용한 것을 후회하게됩니다.
Adrian McCarthy

답변:


11

vector에는 올바른 유형을 알려주는 typedef가 있습니다.

for(std::vector<int>::size_type i = 0; i < thing.size(); ++i)
{
}

거의 항상 size_t로 정의되지만 그에 의존 할 수는 없습니다.


8
가독성의 향상은 아닙니다. IMHO.
Doc Brown

아니요. 그러나 벡터에 대한 인덱스에 사용할 올바른 유형이 무엇인지 알 수있는 유일한 방법이므로 실제로는 중요하지 않습니다.
JohnB

4
요즘 c ++ 11에서는 자동을 사용합니다
JohnB

6
@JohnB 당신은 같은 의미 auto i = 0입니까? 그건 전혀 도움이되지 않습니다 iint.
천정

1
가독성을 향상시킬 수 있습니다 using index_t = std::vector<int>::size_type;.
Toby Speight

4
std::vector<int> vec;

for(int i = 0; i < vec.size(); ++i)

for루프가 아닌 반복자를 사용하십시오 .

다른 사람을 위해, 한 변수 유형은 같은 크기이기 때문에, static_cast잘 작동합니다 (예 DWORDint16_t)


2
for (std::vector<int>::iterator i = vec.begin(); i != vec.end(); ++i)쓰는 고통입니다. 갖는 for (auto i = vec.begin();...것은 훨씬 더 읽기 쉽습니다. 물론 foreachC ++ 11에도 있습니다.
David Thornley

3

설명 한 사례는 C ++에서 싫어하는 것 중 하나입니다. 그러나 나는 그것을 사용하여 그와 함께 사는 법을 배웠습니다.

for( size_t i = 0; i < vec.size(); i++ )

또는

for( int i = 0; i < (int)vec.size(); i++ )

(물론, 후자는 int 오버플로가 발생할 위험이없는 경우에만).


3

부호있는 것과 부호없는 것의 비교에 대해 경고하는 이유는 부호있는 값이 부호없는 것으로 변환 될 가능성이 높기 때문입니다.

당신의 예에서 (비교 intsize_t), int암시 적으로 변환됩니다 size_t(하지 않는 한 int어떻게 든보다 더 큰 범위를 가지고 size_t). 따라서 int가 음수이면 랩 어라운드로 인해 비교하는 값보다 클 수 있습니다. 색인이 음수 인 경우에는 문제가되지 않지만 여전히 경고가 표시됩니다.

대신, 부호없는 형식을 (예 : 사용 unsigned int, size_t로, 또는 존 B 권장 , std::vector<int>::size_type색인 변수) :

for(unsigned int i = 0; i < vec.size(); i++)

카운트 다운 할 때주의하십시오 :

for(unsigned int i = vec.size()-1; i >= 0; i--) // don't do this!

부호가없는 i >= 0경우 항상 참 이므로 위의 방법은 작동하지 않습니다 i. 대신 카운트 다운하는 루프에 " 화살표 연산자 "를 사용하십시오 .

for (unsigned int i = vec.size(); i-- > 0; )
    vec[i] = ...;

다른 답변에서 지적했듯이 일반적으로 반복자를 사용하여 a를 통과하려고 vector합니다. 다음은 C ++ 11 구문입니다.

for (auto i = vec.begin(); i != vec.end(); ++i)

1
이로 인해 여전히 unsigned int크기가 충분하지 않을 위험이 있습니다 .
Adrian McCarthy

2

C ++ 11의 새로운 옵션으로 다음과 같은 작업을 수행 할 수 있습니다.

for(decltype(vec.size()) i = 0; i < vec.size(); ++i) {...}

for(decltype(dWord) i = 0; i < dWord; ++i) {...}

기본 for-loop보다 약간 더 많이 반복되지만, '11 이전 이전의 값 지정 방법만큼 오래 걸리지 않으며이 패턴을 일관되게 사용하면 가능한 모든 용어에 대해 일관되게 작동합니다 코드 리팩토링에 적합합니다. 다음과 같은 간단한 경우에도 작동합니다.

int x = 3; int final = 32; for(decltype(final) i = x; i < final; ++i)

또한 (와 같은 ) 지능형 값으로 auto설정할 때마다 사용해야 하지만 0과 같은 상수로 설정할 때 작동합니다 .0은 간단한 정수 리터럴이므로 자동으로 해결합니다 .ivec.begin()decltypeint

솔직히 말해서 auto루프 증 분기의 유형 결정을 확장하여 비교되는 값 을 볼 수있는 컴파일러 메커니즘을보고 싶습니다 .


1

에서와 같이 캐스트를 int로 사용합니다 for (int i = 0; i < (int)v.size(); ++i). 예, 추악합니다. 표준 라이브러리의 어리석은 디자인에 대해 서명하지 않은 정수를 사용하여 크기를 나타내기로 결정했습니다. (.. 무엇? 범위를 1 비트 연장 하시겠습니까?)


1
어떤 상황에서 부정적인 것의 수집 크기가 의미가 있습니까? 다양한 컬렉션 크기에 부호없는 정수를 사용하는 것은 합리적인 선택 처럼 보입니다 . 마지막으로 확인, 문자열의 길이를 복용하면 거의 부정적인 결과를 거의 반환하지 않습니다 ...
CVn

1
if(v.size()-1 > 0) { ... }빈 컨테이너에 대해 true를 반환하는 것과 같은 간단한 테스트에는 어떤 상황에서 의미가 있습니까? 문제는 크기가 종종 산술에도 사용된다는 것입니다. 인덱스 기반 컨테이너를 사용하면 서명되지 않은 문제가 발생합니다. 기본적으로 1) 비트 조작 또는 2) 모듈 식 산술 이외의 다른 용도로 부호없는 유형을 사용하면 문제가 발생합니다.
zvrba

2
좋은 지적. 나는 당신의 특정 예의 요점을 실제로 보지 못하지만 ( if(v.size() > 1) { ... }그러면 의도를보다 명확하게하고 아마도 추가 보너스로 부호가 있거나 부호가없는 문제가 무효화되기 때문에 글을 쓸 것입니다 ), 어떤 경우에는 어떻게 보입니까 서명이 유용 할 수 있습니다. 나는 정정되었다.
CVn

1
@ 마이클 : 나는 그것이 예를 들어 고안된 것에 동의합니다. 여전히 중첩 루프가있는 알고리즘을 작성하는 경우가 많습니다. for (i = 0; i <v.size ()-1; ++ i) for (j = i + 1; j <v.size (); ++ j) .. v가 비어 있으면 외부 루프가 (size_t) -1 번 실행됩니다. 따라서 루프 전에 v.empty ()를 확인하거나 v.size ()를 서명 된 유형으로 캐스팅해야합니다. 두 가지 모두 개인적으로 추악한 해결 방법이라고 생각합니다. LOC가 적고 실수로 가능성이 적은 캐스트를 선택합니다. 또한 두 번째 보수에서 변환 oveflow는 음수를 반환하므로 루프가 전혀 실행되지 않습니다.
zvrba

범위를 1 비트로 확장하는 것은 16 비트 시스템에서 매우 유용했습니다.
Adrian McCarthy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.