범위 기반 ‘for’루프가 많은 간단한 알고리즘을 사용하지 않습니까? 루프 솔루션

알고리즘 솔루션 :

std::generate(numbers.begin(), numbers.end(), rand);

범위 기반 for 루프 솔루션 :

for (int& x : numbers) x = rand();

std::generateC ++ 11에서 범위 기반 for 루프에 대해 더 자세한 정보를 사용하려는 이유는 무엇 입니까?



답변

첫 번째 버전

std::generate(numbers.begin(), numbers.end(), rand);

일련의 값을 생성하고자 함을 알려줍니다.

두 번째 버전에서는 독자가 스스로 알아 내야합니다.

입력 시간을 절약하는 것은 대개 읽기 시간에 손실되기 때문에 차선책입니다. 대부분의 코드는 입력 한 것보다 훨씬 더 많이 읽습니다.


답변

for 루프가 범위 기반인지 여부에 관계없이 전혀 차이가 없지만 괄호 안의 코드 만 단순화됩니다. 알고리즘은 의도 를 표시한다는 점에서 더 명확합니다 .


답변

개인적으로 처음 읽은 내용 :

std::generate(numbers.begin(), numbers.end(), rand);

“우리는 범위의 모든 것에 할당하고 있습니다. 범위는 numbers 입니다. 할당 된 값은 무작위입니다.”

나의 초기 독서 :

for (int& x : numbers) x = rand();

“우리는 범위 내의 모든 것에 무언가를하고 있습니다. 범위는 numbers 입니다. 우리가하는 일은 임의의 값을 할당하는 것입니다.”

그것들은 상당히 비슷하지만 동일하지는 않습니다. 내가 첫 번째 독서를 유발하고 싶은 한 가지 그럴듯한 이유는이 코드에 대한 가장 중요한 사실이 범위에 할당된다는 것입니다. 그래서 당신의 “내가 왜 …” generateC ++에서 std::generate“범위 할당”을 의미 하기 때문에 사용 합니다. btw가하는 것처럼 std::copy둘의 차이점은 당신이 할당하는 것입니다.

하지만 혼란스러운 요소가 있습니다. 범위 기반 for 루프는 numbers반복기 기반 알고리즘보다 범위가임을 본질적으로보다 직접적인 방식으로 표현합니다 . 이것이 사람들이 범위 기반 알고리즘 라이브러리에서 작업하는 이유 입니다. 버전 boost::range::generate(numbers, rand);보다 낫습니다 std::generate.

반대로 int&범위 기반 for 루프에는 주름이 있습니다. 범위의 값 유형이가 아닌 int경우 여기에서 변환 가능 여부에 의존하는 성가신 미묘한 작업을 수행하는 int&반면 generate코드 rand는 요소에 할당 할 수있는 결과에만 의존합니다 . 값 유형이라고 int해도 나는 그것이 아닌지 생각하기 위해 멈출 수 있습니다. 따라서 auto할당 된 내용을 볼 때까지 유형에 대한 생각을 연기 auto &x합니다. “어떤 유형이 있든지간에 범위 요소에 대한 참조를 가져옵니다”라고 말합니다. (그들이있는 거 기능 템플릿 때문에)이었다 돌아 가기 C ++ 03, 알고리즘 정확한 유형을 숨길 수있는 방법, 지금은있어 방법.

나는 항상 가장 단순한 알고리즘이 동등한 루프에 비해 미미한 이점만을 가지고있는 경우라고 생각합니다. 범위 기반 for 루프는 루프를 개선합니다. 따라서 여백이 더 좁아지고 특정 경우에 마음이 바뀔 수 있습니다. 하지만 여전히 스타일 차이가 있습니다.


답변

내 생각에, Effective STL Item 43 : “수기 루프보다 알고리즘 호출을 선호하십시오.” 여전히 좋은 조언입니다.

나는 보통 begin()/ end()지옥을 제거하기 위해 래퍼 함수를 ​​작성 합니다. 그렇게하면 예제는 다음과 같습니다.

my_util::generate(numbers, rand);

나는 의도전달하고 가독성에서 모두 for 루프 기반 범위를 능가한다고 생각합니다 .


그렇긴하지만 C ++ 98에서 일부 STL 알고리즘 호출이 발화 할 수없는 코드를 생성했으며 “수작업으로 작성한 루프보다 알고리즘 호출 선호”를 따르는 것이 좋은 생각이 아닌 것 같음을 인정해야합니다. 다행히 람다가이를 변경했습니다.

Herb Sutter 의 다음 예제를 고려하십시오 . Lambdas, Lambdas Everywhere .

과제 : v의 첫 번째 요소 인 > xand를 찾습니다 < y.

람다없이 :

auto i = find_if( v.begin(), v.end(),
bind( logical_and<bool>(),
bind(greater<int>(), _1, x),
bind(less<int>(), _1, y) ) );

람다와 함께

auto i=find_if( v.begin(), v.end(), [=](int i) { return i > x && i < y; } );


답변

에서 상세를 줄일 수 있지만 의견, 수동 루프는, readabitly 부족 :

for (int& x : numbers) x = rand();

나는 초기화이 루프를 사용하지 않을 에 의해 정의 된 범위의 숫자를 내가 볼 때, 그것이 나에게 것 때문에, 이상 반복하는을 , 숫자의 범위,하지만 실제로는 (본질적으로)하지 않는 즉, 대신 범위에서 읽기 , 그것은 쓰는 .

를 사용하면 의도가 훨씬 더 명확 해 std::generate집니다.

1. 이 컨텍스트에서 초기화 는 컨테이너의 요소에 의미있는 값을 제공하는 것을 의미 합니다.


답변

반복기를 입력으로 취하는 알고리즘이 할 수있는 범위 기반 루프로는 (간단히) 할 수없는 일이 있습니다. 예를 들어std::generate 같습니다.

에 컨테이너 채워 limit제외 (를 limit유효한 반복자에이다numbers 를 한 분포의 변수로 나머지는 다른 분포의 변수 임) 채 .

std::generate(numbers.begin(), limit, rand1);
std::generate(limit, numbers.end(), rand2);

반복자 기반 알고리즘을 사용하면 작업중인 범위를 더 잘 제어 할 수 있습니다.


답변

의 특정 사례 std::generate에 대해서는 가독성 / 의도 문제에 대한 이전 답변에 동의합니다. std :: generate는 나에게 더 명확한 버전으로 보입니다. 그러나 나는 이것이 맛의 문제임을 인정합니다.

즉, std :: algorithm을 버리지 않는 또 다른 이유가 있습니다. 일부 데이터 유형에 특화된 특정 알고리즘이 있습니다.

가장 간단한 예는 std::fill. 일반 버전은 제공된 범위에 대해 for 루프로 구현되며이 버전은 템플릿을 인스턴스화 할 때 사용됩니다. 하지만 항상 그런 것은 아닙니다. 예를 들어 범위를 제공 std::vector<int>하면 실제로 호출됩니다.memset 하여 훨씬 빠르고 더 나은 코드를 생성합니다.

그래서 저는 여기서 효율성 카드를 사용하려고합니다.

손으로 쓴 루프는 std :: algorithm 버전만큼 빠르지 만 거의 빠를 수 없습니다. 뿐만 아니라 std :: algorithm은 특정 컨테이너 및 유형에 특화 될 수 있으며 깨끗한 STL 인터페이스에서 수행됩니다.