Programming

최신 C ++로 무료 성능을 얻을 수 있습니까?

procodes 2020. 5. 6. 22:13
반응형

최신 C ++로 무료 성능을 얻을 수 있습니까?


C ++ 11/14는 단지 C ++ 98 코드를 컴파일 할 때에도 성능을 향상시킬 수 있다고 주장합니다. 일부 경우 rvalue 생성자가 자동으로 생성되거나 이제는 STL의 일부이므로 정당화는 일반적으로 이동 의미론을 따릅니다. 이제 이러한 사례가 실제로 RVO 또는 유사한 컴파일러 최적화로 이미 처리되었는지 궁금합니다.

내 질문은 수정없이 새로운 언어 기능을 지원하는 컴파일러를 사용하여 더 빨리 실행되는 C ++ 98 코드의 실제 예를 나에게 줄 수 있는지 여부입니다. 필자는 표준 준수 컴파일러가 복사 제거를 수행 할 필요가 없으며 이동 시맨틱으로 인해 속도가 향상 될 수 있음을 이해하지만 병리학 적 사례를보고 싶습니다.

편집 : 명확하게 말하면, 새로운 컴파일러가 이전 컴파일러보다 빠른지 묻지 않고 컴파일러 플래그에 -std = c ++ 14를 추가하는 코드가 있으면 더 빨리 실행됩니다 (복사본은 피하십시오) 이동 의미론 외에 다른 것을 생각 해낼 수 있습니다.


C ++ 11로 C ++ 03 컴파일러를 다시 컴파일하면 구현 품질과 실질적으로 관련이없는 무한한 성능 향상이 발생할 수있는 5 가지 일반적인 범주를 알고 있습니다. 이것들은 모두 이동 의미의 변형입니다.

std::vector 재 할당

struct bar{
  std::vector<int> data;
};
std::vector<bar> foo(1);
foo.back().data.push_back(3);
foo.reserve(10); // two allocations and a delete occur in C++03

마다 foo의 버퍼가 03 C ++로 재 할당은 모든 복사 vectorbar.

C ++ 11에서는 대신 bar::data기본적으로 무료 인 s 를 이동합니다 .

이 경우 std컨테이너 내부의 최적화에 의존합니다 vector. 아래의 모든 경우에 std컨테이너를 사용하는 move것은 컴파일러를 업그레이드 할 때 C ++ 11에서 "자동"으로 효율적인 의미 를 갖는 C ++ 객체이기 때문 입니다. std컨테이너 를 포함하는 컨테이너를 차단하지 않는 개체 도 자동으로 개선 된 move생성자를 상속합니다 .

NRVO 실패

NRVO (이름 반환 값 최적화)가 실패하면 C ++ 03에서는 복사시, C ++ 11에서는 이동시 돌아갑니다. NRVO의 실패는 쉽다 :

std::vector<int> foo(int count){
  std::vector<int> v; // oops
  if (count<=0) return std::vector<int>();
  v.reserve(count);
  for(int i=0;i<count;++i)
    v.push_back(i);
  return v;
}

또는:

std::vector<int> foo(bool which) {
  std::vector<int> a, b;
  // do work, filling a and b, using the other for calculations
  if (which)
    return a;
  else
    return b;
}

우리는 세 가지 값, 즉 반환 값과 함수 내에서 다른 두 값을 가지고 있습니다. Elision을 사용하면 함수 내의 값이 반환 값과 '병합'되지만 서로는 병합되지 않습니다. 서로 병합하지 않고 반환 값과 병합 할 수 없습니다.

기본적인 문제는 NRVO 제거가 취약하고 return사이트 근처가 아닌 변경 사항이있는 코드가 갑자기 진단을받지 않고 해당 지점에서 성능이 크게 저하 될 수 있다는 것입니다. 대부분의 NRVO 실패 사례에서 C ++ 11은로 끝나고 moveC ++ 03은 복사본으로 끝난다.

함수 인수 반환

여기에서도 제거가 불가능합니다 :

std::set<int> func(std::set<int> in){
  return in;
}

C ++ 11에서는 저렴합니다. C ++ 03에서는 복사를 피할 수있는 방법이 없습니다. 매개 변수 및 리턴 값의 수명 및 위치는 호출 코드로 관리되므로 함수에 대한 인수는 리턴 값으로 제거 할 수 없습니다.

그러나 C ++ 11은 서로 이동할 수 있습니다. 장난감이 적은 예에서는 무언가가 수행 될 수 있습니다 set.

push_back 또는 insert

마지막으로 컨테이너로의 제거는 발생하지 않지만 C ++ 11은 rvalue 이동 삽입 연산자를 오버로드하여 사본을 저장합니다.

struct whatever {
  std::string data;
  int count;
  whatever( std::string d, int c ):data(d), count(c) {}
};
std::vector<whatever> v;
v.push_back( whatever("some long string goes here", 3) );

C ++ 03에서 임시 whatever가 생성 된 다음 vector에 복사됩니다 v. std::string각각 동일한 데이터를 갖는 2 개의 버퍼가 할당되고 하나는 버려집니다.

In C++11 a temporary whatever is created. The whatever&& push_back overload then moves that temporary into the vector v. One std::string buffer is allocated, and moved into the vector. An empty std::string is discarded.

Assignment

Stolen from @Jarod42's answer below.

Elision cannot occur with assignment, but move-from can.

std::set<int> some_function();

std::set<int> some_value;

// code

some_value = some_function();

here some_function returns a candidate to elide from, but because it is not used to construct an object directly, it cannot be elided. In C++03, the above results in the contents of the temporary being copied into some_value. In C++11, it is moved into some_value, which basically is free.


For the full effect of the above, you need a compiler that synthesizes move constructors and assignment for you.

MSVC 2013 implements move constructors in std containers, but does not synthesize move constructors on your types.

So types containing std::vectors and similar do not get such improvements in MSVC2013, but will start getting them in MSVC2015.

clang and gcc have long since implemented implicit move constructors. Intel's 2013 compiler will support implicit generation of move constructors if you pass -Qoption,cpp,--gen_move_operations (they don't do it by default in an effort to be cross-compatible with MSVC2013).


if you have something like:

std::vector<int> foo(); // function declaration.
std::vector<int> v;

// some code

v = foo();

You got a copy in C++03, whereas you got a move assignment in C++11. so you have free optimisation in that case.

참고URL : https://stackoverflow.com/questions/27595429/can-modern-c-get-you-performance-for-free

반응형