std :: vector에 대한 반복 : 부호없는 vs 부호있는 인덱스 변수
C ++에서 벡터를 반복하는 올바른 방법은 무엇입니까?
이 두 코드 조각을 고려하십시오.이 코드는 잘 작동합니다.
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
그리고 이것:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
생성 warning: comparison between signed and unsigned integer expressions
합니다.
나는 C ++의 세계에서 처음 unsigned
왔 으므로 변수가 약간 무섭게 보이며 unsigned
올바르게 사용하지 않으면 변수가 위험 할 수 있다는 것을 알고 있습니다. 맞습니까?
거꾸로 반복
이 답변을 참조하십시오 .
앞으로 반복
이것은 거의 동일합니다. 반복자 / 스왑 감소를 증분 단위로 변경하십시오. 반복자를 선호해야합니다. 어떤 사람들 std::size_t
은 색인 변수 유형 으로 사용하라고 말합니다 . 그러나 그것은 휴대용이 아닙니다. 항상 사용 size_type
(당신이 앞으로 반복하는 경우에만 변환 넘어갈 수 있지만 사용하는 경우, 실제로 후진을 반복하는 경우에 모든 방법을 잘못 될 수있는 컨테이너의 타입 정의를 std::size_t
경우 std::size_t
의 형식 정의 무엇보다 넓은 size_type
) :
std :: vector 사용
반복자 사용
for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
/* std::cout << *it; ... */
}
중요한 것은, 정의를 모르는 반복자에는 항상 접두사 증가 양식을 사용하는 것입니다. 그러면 코드가 가능한 한 일반적으로 실행됩니다.
Range C ++ 11 사용
for(auto const& value: a) {
/* std::cout << value; ... */
인덱스 사용
for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
/* std::cout << v[i]; ... */
}
배열 사용
반복자 사용
for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
/* std::cout << *it; ... */
}
Range C ++ 11 사용
for(auto const& value: a) {
/* std::cout << value; ... */
인덱스 사용
for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
/* std::cout << a[i]; ... */
}
sizeof
그러나 접근 방식이 어떤 문제를 일으킬 수 있는지 거꾸로 반복되는 답변을 읽으십시오 .
4 년이 지났는데 구글 이이 답을 주었다. 와 표준 C ++ 11 (일명 C ++ 0X 새로운 :) 실제로 (이전 버전과의 호환성을 깨는의 가격)이 일을 새로운 기분 좋은 방법이 auto
키워드. 컴파일러가 사용하는 유형이 분명 할 때 사용할 반복기 유형 (벡터 유형을 다시 반복)을 명시 적으로 지정해야하는 번거 로움을 덜어줍니다. 으로 v
당신 인 vector
, 당신은 이런 식으로 뭔가를 할 수 있습니다 :
for ( auto i = v.begin(); i != v.end(); i++ ) {
std::cout << *i << std::endl;
}
C ++ 11 은 더 나아가서 벡터와 같은 컬렉션을 반복하는 특수 구문을 제공합니다. 항상 같은 내용을 작성할 필요가 없습니다.
for ( auto &i : v ) {
std::cout << i << std::endl;
}
작동하는 프로그램에서 파일을 보려면 파일을 빌드하십시오 auto.cpp
.
#include <vector>
#include <iostream>
int main(void) {
std::vector<int> v = std::vector<int>();
v.push_back(17);
v.push_back(12);
v.push_back(23);
v.push_back(42);
for ( auto &i : v ) {
std::cout << i << std::endl;
}
return 0;
}
이 글을 쓰는 시점에서 g ++로 컴파일 할 때 일반적으로 추가 플래그를 지정하여 새 표준과 작동하도록 설정해야합니다.
g++ -std=c++0x -o auto auto.cpp
이제 예제를 실행할 수 있습니다.
$ ./auto
17
12
23
42
참고 컴파일 및 실행에 대한 지침은 특정 것을 GNU C ++ 의 컴파일러 리눅스 , 프로그램은 플랫폼 (및 컴파일러) 독립적이어야한다.
귀하의 예에서 특정 경우에는 STL 알고리즘을 사용하여이를 수행합니다.
#include <numeric>
sum = std::accumulate( polygon.begin(), polygon.end(), 0 );
보다 일반적이지만 여전히 간단한 경우를 위해 다음과 같이하겠습니다.
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );
Johannes Schaub의 답변에 관하여 :
for(std::vector<T*>::iterator it = v.begin(); it != v.end(); ++it) {
...
}
일부 컴파일러에서는 작동하지만 gcc에서는 작동하지 않을 수 있습니다. std :: vector :: iterator가 유형, 변수 (멤버) 또는 함수 (메서드) 인 경우 문제가 있습니다. gcc에 다음과 같은 오류가 발생합니다.
In member function ‘void MyClass<T>::myMethod()’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In member function ‘void MyClass<T>::sort() [with T = MyClass]’:
instantiated from ‘void MyClass<T>::run() [with T = MyClass]’
instantiated from here
dependent-name ‘std::vector<T*,std::allocator<T*> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<T*,std::allocator<T*> >::iterator’ if a type is meant
해결책은 다음과 같이 키워드 'typename'을 사용하고 있습니다.
typename std::vector<T*>::iterator it = v.begin();
for( ; it != v.end(); ++it) {
...
를 호출하면 int, unsigned int 등이 아닌 vector<T>::size()
type 값 을 반환합니다 std::vector<T>::size_type
.
또한 일반적으로 C ++에서 컨테이너에 대한 반복은 이와 같은 반복자를 사용하여 수행됩니다 .
std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();
for(; i != end; i++){
sum += *i;
}
여기서 T는 벡터에 저장하는 데이터 유형입니다.
또는 다른 반복 알고리즘을 사용하여 ( std::transform
, std::copy
, std::fill
, std::for_each
등등).
사용 size_t
:
for (size_t i=0; i < polygon.size(); i++)
인용 위키 백과 :
stdlib.h 및 stddef.h 헤더 파일
size_t
은 객체의 크기를 나타내는 데 사용되는 데이터 유형을 정의 합니다. 크기를 취하는 라이브러리 함수는 형식이 될 것으로 예상하고size_t
sizeof 연산자는 다음과 같이 평가됩니다size_t
.실제 유형
size_t
은 플랫폼에 따라 다릅니다. 일반적인 실수는size_t
부호없는 int와 같다고 가정 하는 것인데, 이는 특히 64 비트 아키텍처가 널리 보급됨에 따라 프로그래밍 오류로 이어질 수 있습니다.
약간의 역사 :
숫자가 음수인지 아닌지를 나타내려면 'sign'비트를 사용하십시오. int
부호있는 데이터 유형으로 양수 및 음수 값 (약 -2 십억-20 억)을 보유 할 수 있습니다. Unsigned
양수 만 저장할 수 있습니다 (메타 데이터를 조금 낭비하지 않기 때문에 더 많이 저장할 수 있습니다 : 0 ~ 약 40 억).
std::vector::size()
반환 unsigned
벡터가 음의 길이를 가질 수 방법은?
경고는 부등식의 오른쪽 피연산자가 왼쪽보다 많은 데이터를 보유 할 수 있음을 알려줍니다.
본질적으로 20 억 개 이상의 항목이있는 벡터가 있고 정수를 사용하여 색인을 생성하면 오버플로 문제가 발생합니다 (int는 음의 20 억으로 줄어 듭니다).
나는 보통 BOOST_FOREACH를 사용합니다.
#include <boost/foreach.hpp>
BOOST_FOREACH( vector_type::value_type& value, v ) {
// do something with 'value'
}
STL 컨테이너, 배열, C 스타일 문자열 등에서 작동합니다.
완료하려면 C ++ 11 구문을 사용하면 반복기 ( ref )에 대해 다른 버전 만 사용할 수 있습니다 .
for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
// do something with *it
}
역 반복에도 편안한
for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
// do something with *it
}
C ++ 11에서
for_each
여분의 명명 된 함수 / 객체를 피하기 위해 올바른 유형의 반복자와 람다 식을 검색하지 않으려는 것과 같은 일반적인 알고리즘을 사용 합니다.
특정 경우에 대한 간단한 "예쁜"예 (다각형이 정수로 구성된 벡터라고 가정) :
for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; });
테스트 : http://ideone.com/i6Ethd
다음 을 포함하는 것을 잊지 마십시오 : 알고리즘과 물론 vector :)
Microsoft는 실제로 이것에 대한 좋은 예를 가지고 있습니다 :
source : http://msdn.microsoft.com/en-us/library/dd293608.aspx
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// Create a vector object that contains 10 elements.
vector<int> v;
for (int i = 1; i < 10; ++i) {
v.push_back(i);
}
// Count the number of even numbers in the vector by
// using the for_each function and a lambda.
int evenCount = 0;
for_each(v.begin(), v.end(), [&evenCount] (int n) {
cout << n;
if (n % 2 == 0) {
cout << " is even " << endl;
++evenCount;
} else {
cout << " is odd " << endl;
}
});
// Print the count of even numbers to the console.
cout << "There are " << evenCount
<< " even numbers in the vector." << endl;
}
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
sum += *it;
첫 번째는 형식이 정확하고 엄격한 의미에서 올바른 것입니다. (당신이 생각한다면, 크기는 0보다 작을 수 없습니다.) 그 경고는 나를 무시할 수있는 좋은 후보 중 하나라고 생각합니다.
전혀 반복해야하는지 고려하십시오
<algorithm>
표준 헤더는이 시설을 우리에게 제공합니다 :
using std::begin; // allows argument-dependent lookup even
using std::end; // if the container type is unknown here
auto sum = std::accumulate(begin(polygon), end(polygon), 0);
알고리즘 라이브러리의 다른 기능은 일반적인 작업을 수행합니다. 노력을 절약하려면 사용 가능한 기능을 알고 있어야합니다.
모호하지만 중요한 세부 사항 : 다음과 같이 "for (auto it)"라고 말하면 실제 요소가 아닌 오브젝트의 사본을 얻습니다.
struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
it.i = 1; // doesn't change the element v[0]
벡터의 요소를 수정하려면 반복자를 참조로 정의해야합니다.
for(auto &it : v)
컴파일러에서 지원하는 경우 벡터 요소에 액세스하기 위해 범위를 사용할 수 있습니다.
vector<float> vertices{ 1.0, 2.0, 3.0 };
for(float vertex: vertices){
std::cout << vertex << " ";
}
인쇄 : 1 2 3. 이 기법을 사용하여 벡터 요소를 변경할 수는 없습니다.
두 코드 세그먼트는 동일하게 작동합니다. 그러나 부호없는 int "라우트는 정확합니다. 부호없는 int 유형을 사용하면 사용한 인스턴스의 벡터에서 더 잘 작동합니다. 벡터에서 size () 멤버 함수를 호출하면 부호없는 정수 값이 반환되므로 변수를 비교하려고합니다. "i"는 고유 한 유형의 값입니다.
또한 "unsigned int"가 코드에서 어떻게 보이는지에 대해 조금 불안하다면 "uint"를 사용해보십시오. 이것은 기본적으로 "unsigned int"의 단축 버전이며 정확히 동일하게 작동합니다. 또한 다른 헤더를 사용하지 않아도 사용할 수 있습니다.
'Programming' 카테고리의 다른 글
Python 프로그램을 50 밀리 초 동안 잠자 게하려면 어떻게해야합니까? (0) | 2020.02.16 |
---|---|
유형 또는 네임 스페이스 이름을 찾을 수 없습니다. (0) | 2020.02.16 |
Android의 다른 애플리케이션에서 애플리케이션을 실행하십시오. (0) | 2020.02.16 |
NSString에 퍼센트 부호를 추가하는 방법 (0) | 2020.02.16 |
UTF-8과 유니 코드의 차이점은 무엇입니까? (0) | 2020.02.16 |