작성
·
411
·
수정됨
2
vector<Base*> vec;
for(auto& el : vec)
el->print();
vector<reference_wrapper<Base>> vec;
for(auto& el : vec)
el.get().print();
레퍼런스가 포인터보다 빠르지만 위에서는
get() 함수를 호출하니까 함수호출하면 스택프레임 전개되는데
이러면 오히려 오버헤드가 더 커지는것 아닌가요?
궁금해서 질문 올립니다.
답변 1
5
안녕하세요, 답변 도우미 Soobak 입니다.
std::reference_wrapper
의 get()
함수는 레퍼런스를 반환하는 매우 간단한 함수입니다.
따라서, 최적화가 활성화된 컴파일러에서의 get()
함수 호출은 실제로 함수 호출 오버헤드가 거의 없을 것 같습니다. (컴파일러가 get()
함수의 호출을 인라인화 하여 오버헤드를 제거할 수 있습니다.)
따라서, get()
함수 호출의 오버헤드는 컴파일러와 환경마다 다르겠지만, 실제 오버헤드는 거의 없거나 크지 않을 것 같습니다.
프로그램의 성능에 관하여 결론을 내리려면, 실제로 프로파일링을 해보는 것이 좋은 방법 중 하나라고 생각하여 직접 1,000,000
번의 호출에 대한 프로파일링을 수행하여 결과를 첨부드립니다.
Pointer 사용
10회 테스트 결과
6117478
ms
5987689
ms
5597883
ms
5983082
ms
6165754
ms
5846662
ms
6058912
ms
6148422
ms
5992986
ms
5949786
ms
평균 : 5984865.4
ms
Reference_wrapper 사용
10회 테스트 결과
5692842
ms
5974881
ms
5836269
ms
5824138
ms
5613559
ms
5926921
ms
5619935
ms
5969758
ms
5769026
ms
5755576
ms
평균 : 5798290.5
ms
또한, 추가적으로 std::reference_warpper
의 사용에 대해서는 가독성, 안전성 등의 장점이 있다는 것도 고려해보시면 좋을 것 같습니다.
테스트 코드를 첨부드립니다.
#include <iostream>
#include <vector>
#include <functional>
#include <chrono>
using namespace std;
class Base {
public:
virtual void print() const {
cout << "Base" << endl;
}
};
class Derived : public Base {
public:
virtual void print() const override {
cout << "Derived" << endl;
}
};
int main() {
const int num_elements = 1'000'000;
Base b;
Derived d;
vector<Base*> ptr_vec;
for (int i = 0; i < num_elements; i++) {
ptr_vec.push_back(&b);
ptr_vec.push_back(&d);
}
vector<reference_wrapper<Base>> ref_vec;
for (int i = 0; i < num_elements; i++) {
ref_vec.push_back(b);
ref_vec.push_back(d);
}
// Pointer 사용 버전
auto start_time = chrono::high_resolution_clock::now();
for (auto& el : ptr_vec) {
el->print();
}
auto end_time = chrono::high_resolution_clock::now();
auto duration_pointer = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
cout << "Pointer version took: " << duration_pointer << " microseconds" << endl;
// reference_wrapper 사용 버전
start_time = chrono::high_resolution_clock::now();
for (auto& el : ref_vec) {
el.get().print();
}
end_time = chrono::high_resolution_clock::now();
auto duration_refwrapper = chrono::duration_cast<chrono::microseconds>(end_time - start_time).count();
cout << "Reference wrapper version took: " << duration_refwrapper << " microseconds" << endl;
return 0;
}
이렇게 친절한 답변을!
간단하게 답변을 해주셔도 되는데 감동의 답변입니다!
좋은 지식 감사합니다.