C ++ 11 범위 기반 루프 : 값으로 항목 가져 오기 또는 const 참조


215

범위 기반 루프의 몇 가지 예를 읽으면 두 가지 주요 방법 1 , 2 , 3 , 4 를 제안합니다.

std::vector<MyClass> vec;

for (auto &x : vec)
{
  // x is a reference to an item of vec
  // We can change vec's items by changing x 
}

또는

for (auto x : vec)
{
  // Value of x is copied from an item of vec
  // We can not change vec's items by changing x
}

잘.

vec항목을 변경할 필요가없는 경우 IMO, 예제에서는 두 번째 버전 (값 기준)을 사용하는 것이 좋습니다. 그들이 const참조 하는 것을 제안하지 않는 이유 (적어도 직접적인 제안은 찾지 못했습니다) :

for (auto const &x : vec) // <-- see const keyword
{
  // x is a reference to an const item of vec
  // We can not change vec's items by changing x 
}

더 좋지 않습니까? 그것이 반복되는 동안 각 반복에서 중복 사본을 피하지 const않습니까?

답변:


390

항목을 변경하지 않고 사본을 만들지 않으 려면 auto const &올바른 선택입니다.

for (auto const &x : vec)

당신이 사용하도록 제안하는 사람 auto &은 잘못입니다. 그들을 무시하라.

요약하면 다음과 같습니다.

  • auto x사본으로 작업 할 시간을 선택하십시오 .
  • auto &x원본 항목으로 작업 할 때 선택 하면 수정 될 수 있습니다.
  • auto const &x원본 항목으로 작업 할 때 선택 하면 수정되지 않습니다.

21
큰 답변 주셔서 감사합니다. 나는 const auto &x당신의 세 번째 선택과 동등한 것이 지적되어야한다고 생각합니다 .
smg 2016

7
@ mloskot : 동일합니다. (그리고 "동일한 구문" 이란 무엇입니까? 구문은 상당히 다릅니다.)
Nawaz

14
누락 : auto&&불필요하게 사본을 만들고 싶지 않고 수정 여부를 신경 쓰지 않고 작업하고 싶을 때.
Yakk-Adam Nevraumont

4
int / double과 같은 기본 유형으로 작업하는 경우 사본에 참조 구별이 적용됩니까?

4
@ racarate : 전반적인 속도 에 대해 언급 할 수 없으며 먼저 프로파일 링하지 않고는 아무도 할 수 없다고 생각합니다. 솔직히, 나는 코드의 명확성보다는 속도에 따라 선택을하지 않을 것이다. 불변성을 원한다면 const반드시 사용 하십시오. 그러나이 될 것인지 auto const &, 또는 auto const 약간의 차이가 있습니다. auto const &좀 더 일관성있게 선택하고 싶습니다 .
Nawaz

23

당신이있는 경우 std::vector<int>또는 std::vector<double>, 그것은 사용으로 잘의 auto대신 (값의 사본을) const auto&을 복사하기 때문에, int또는이 double저렴합니다 :

for (auto x : vec)
    ....

하지만이 경우 std::vector<MyClass>, 어디에서 MyClass일부 비 사소한 복사 의미가 있습니다 (예를 들어 std::string, 일부 복잡한 사용자 정의 클래스 등) 그럼 내가 사용하는 것이 좋습니다 것입니다 const auto&깊은 복사본을 피하기 위해 :

for (const auto & x : vec)
    ....

3

vec항목을 변경할 필요가없는 경우 예제는 첫 번째 버전을 사용하는 것이 좋습니다.

그런 다음 그들은 잘못된 제안을합니다.

그들이 const 참조하는 것을 제안하지 않는 이유

그들은 잘못된 제안을하기 때문에 :-) 당신이 언급 한 것은 맞습니다. 객체 만 관찰 하려는 경우 사본을 만들 필요가 없으며 const참조 하지 않아도됩니다 .

편집하다:

나는 당신이 연결하는 참조가 다양한 범위의 int값이나 다른 기본 데이터 유형 을 반복하는 예제를 제공한다는 것을 알았습니다 . 이 경우 복사는 int비용이 많이 들지 않기 때문에 복사본을 만드는 것은 기본적으로을 관찰하는 것보다 효율적이지 않습니다 const &.

그러나 이는 일반적으로 사용자 정의 유형의 경우에는 해당되지 않습니다. UDT는 복사 비용이 많이들 수 있으며, 원본을 변경하지 않고 검색된 객체를 수정하는 등 사본을 생성 할 이유가없는 경우에는을 사용하는 것이 좋습니다 const &.


1

여기서는 반대로 auto const &for 루프 기반 범위에서 필요가 없다고 말합니다 . 다음 기능이 어리석은 것으로 생각되면 알려주십시오 (그 목적이 아니라 작성 방식).

long long SafePop(std::vector<uint32_t>& v)
{
    auto const& cv = v;
    long long n = -1;
    if (!cv.empty())
    {
        n = cv.back();
        v.pop_back();
    }
    return n;
}

여기서 저자는 vv를 수정하지 않는 모든 연산에 사용하기 위해 const 참조를 만들었습니다 . 이것은 어리석은 생각 auto const &입니다. auto &.


3
@ BenjaminLindley : 그래서 당신도 const_iteratorfor 루프에서 논쟁 할 것이라고 추론 할 수 있습니까? 컨테이너를 반복 할 때 컨테이너에서 원본 항목을 변경하지 않으려면 어떻게해야합니까?
Nawaz

2
@ BenjaminLindley : 왜 코드가 없으면 컴파일되지 const_iterator않습니까? 반복자가 사용하는 컨테이너는 const입니다. 그러나 왜 const시작 하는가? 어딘가에 당신이 사용하고 const무엇을 위해?
Nawaz

8
객체를 만드는 const장점은 클래스에서 private/ 를 사용하는 장점과 같습니다 protected. 추가 실수를 피합니다.
masoud

2
@ BenjaminLindley : 아, 나는 그것을 간과했다. 그런 다음이 경우 구현도 바보입니다. 그러나 그 함수가 수정되지 않았다면 v구현은 훌륭한 IMO가 될 것입니다. 그리고 루프가 반복하는 객체를 수정하지 않으면 참조를하는 것이 옳습니다 const. 그래도 요점을 참조하십시오. 내 루프는 함수와 거의 비슷한 코드 단위를 나타내며 해당 단위 에는 값을 수정 해야하는 명령이 없습니다. 따라서 멤버 함수를 const사용하는 것처럼 전체 단위에 "태그"를 지정할 수 있습니다 const.
Andy Prowl

1
그래서 당신은 cv -qualification으로 const &바보 같은 것을 한 가상 프로그래머의 무의미한 가상의 예를 썼기 때문에 범위 기반은 바보 라고 생각 합니까? ... OK
underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.