저는 고성능과 낮은 메모리 오버 헤드를 염두에두고 C ++로 작성된 많은 계산 코드로 작업합니다. STL 컨테이너 (대부분 vector
)를 많이 사용하며 거의 모든 단일 함수에서 해당 컨테이너를 반복합니다.
반복 코드는 다음과 같습니다.
for (int i = 0; i < things.size(); ++i)
{
// ...
}
그러나 서명 된 / 서명되지 않은 불일치 경고 (Visual Studio의 C4018)를 생성합니다.
교체 int
일부 unsigned
유형 우리가 자주의 OpenMP 프라그 마를 사용하기 때문에 문제이며, 그것은으로 카운터가 필요합니다 int
.
나는 (수백 개의) 경고를 억제하려고하는데 문제에 대한 우아한 해결책을 놓친 것 같아 두렵다.
반복자에서 . 반복자는 적절한 장소에 적용될 때 훌륭하다고 생각합니다. 내가 작업중인 코드는 임의 액세스 컨테이너를 또는 다른 것으로 변경 하지 않으며list
(따라서 반복 int i
은 이미 컨테이너에 구애받지 않습니다) 항상 현재 인덱스가 필요합니다. 그리고 입력해야하는 모든 추가 코드 (반복자 자체 및 인덱스)는 문제를 복잡하게 만들고 기본 코드의 단순성을 난독하게 만듭니다.
답변
그것은 모두 당신의 things.size()
유형입니다. 는 int
아니지만 size_t
(C 가 아닌 C ++에 존재) 일부 “일반적인”부호없는 유형, 즉 unsigned int
x86_32에 해당합니다.
연산자 “less”(<)는 부호가 다른 두 피연산자에 적용될 수 없습니다. 그러한 opcode는 없으며 표준은 컴파일러가 암시 적 부호 변환을 수행 할 수 있는지 여부를 지정하지 않습니다. 따라서 부호있는 숫자를 부호없는 것으로 취급하고 경고를 내 보냅니다.
다음과 같이 쓰는 것이 맞을 것입니다.
for (size_t i = 0; i < things.size(); ++i) { /**/ }
또는 더 빠르게
for (size_t i = 0, ilen = things.size(); i < ilen; ++i) { /**/ }
답변
이상적으로는 다음과 같은 구조를 대신 사용합니다.
for (std::vector<your_type>::const_iterator i = things.begin(); i != things.end(); ++i)
{
// if you ever need the distance, you may call std::distance
// it won't cause any overhead because the compiler will likely optimize the call
size_t distance = std::distance(things.begin(), i);
}
이것은 코드가 갑자기 컨테이너에 구애받지 않는 깔끔한 이점이 있습니다.
그리고 문제와 관련하여 사용하는 일부 라이브러리 가 더 적합한 int
곳 에서 사용해야 하는 경우 unsigned int
API가 지저분합니다. 어쨌든, 그것들 int
이 항상 긍정적 이라고 확신한다면 다음과 같이 할 수 있습니다.
int int_distance = static_cast<int>(distance);
컴파일러에 대한 의도를 명확하게 지정합니다. 더 이상 경고로 인해 버그가 발생하지 않습니다.
답변
당신은 / 반복자를 사용하지 않습니다 당신은 / 사용하지 않을 수없는 경우 수없는 경우 std::size_t
루프 인덱스를 들어,을 .size()
에 int
문서 가정이와 변환이 명시 적으로 컴파일러 경고를 침묵 않는 변환 기능.
#include <cassert>
#include <cstddef>
#include <limits>
// When using int loop indexes, use size_as_int(container) instead of
// container.size() in order to document the inherent assumption that the size
// of the container can be represented by an int.
template <typename ContainerType>
/* constexpr */ int size_as_int(const ContainerType &c) {
const auto size = c.size(); // if no auto, use `typename ContainerType::size_type`
assert(size <= static_cast<std::size_t>(std::numeric_limits<int>::max()));
return static_cast<int>(size);
}
그런 다음 다음과 같이 루프를 작성합니다.
for (int i = 0; i < size_as_int(things); ++i) { ... }
이 함수 템플릿의 인스턴스화는 거의 확실하게 인라인됩니다. 디버그 빌드에서는 가정이 확인됩니다. 릴리스 빌드에서는 그렇지 않으며 size ()를 직접 호출 한 것처럼 코드가 빠릅니다. 두 버전 모두 컴파일러 경고를 생성하지 않으며 관용적 루프에 대한 약간의 수정일뿐입니다.
릴리스 버전에서도 가정 실패를 포착하려면 어설 션을 다음과 같은 if 문으로 대체 할 수 있습니다 std::out_of_range("container size exceeds range of int")
.
이렇게하면 부호있는 / 부호없는 비교와 잠재적 인 sizeof(int)
! = sizeof(Container::size_type)
문제가 모두 해결됩니다. 모든 경고를 활성화 된 상태로두고이를 사용하여 코드의 다른 부분에서 실제 버그를 포착 할 수 있습니다.
답변
당신이 사용할 수있는:
- size_t 유형, 경고 메시지 제거
- 반복자 + 거리 (예 : 첫 번째 힌트)
- 반복자 만
- 함수 객체
예를 들면 :
// simple class who output his value
class ConsoleOutput
{
public:
ConsoleOutput(int value):m_value(value) { }
int Value() const { return m_value; }
private:
int m_value;
};
// functional object
class Predicat
{
public:
void operator()(ConsoleOutput const& item)
{
std::cout << item.Value() << std::endl;
}
};
void main()
{
// fill list
std::vector<ConsoleOutput> list;
list.push_back(ConsoleOutput(1));
list.push_back(ConsoleOutput(8));
// 1) using size_t
for (size_t i = 0; i < list.size(); ++i)
{
std::cout << list.at(i).Value() << std::endl;
}
// 2) iterators + distance, for std::distance only non const iterators
std::vector<ConsoleOutput>::iterator itDistance = list.begin(), endDistance = list.end();
for ( ; itDistance != endDistance; ++itDistance)
{
// int or size_t
int const position = static_cast<int>(std::distance(list.begin(), itDistance));
std::cout << list.at(position).Value() << std::endl;
}
// 3) iterators
std::vector<ConsoleOutput>::const_iterator it = list.begin(), end = list.end();
for ( ; it != end; ++it)
{
std::cout << (*it).Value() << std::endl;
}
// 4) functional objects
std::for_each(list.begin(), list.end(), Predicat());
}
답변
C ++ 11에 대한 다음 솔루션을 제안 할 수도 있습니다.
for (auto p = 0U; p < sys.size(); p++) {
}
(C ++는 auto p = 0에 대해 충분히 똑똑하지 않으므로 p = 0U를 넣어야합니다 ….)
답변
더 나은 아이디어를 드릴게요
for(decltype(things.size()) i = 0; i < things.size(); i++){
//...
}
decltype
이다
선언 된 엔터티 유형 또는 식의 유형 및 값 범주를 검사합니다.
따라서의 유형을 추론 things.size()
하고와 i
같은 유형이됩니다 things.size()
. 따라서
i < things.size()
경고없이 실행됩니다.
답변
비슷한 문제가있었습니다. size_t 사용이 작동하지 않았습니다. 나는 나를 위해 일한 다른 것을 시도했습니다. (아래)
for(int i = things.size()-1;i>=0;i--)
{
//...
}