. 함수가 const &에 의해 인수를 취하는 경우 불필요 할 수 있지만 일반적으로 함수에 의해 객체가 변형 될 수 있습니다. 개체를 복사하는 데 비용이 많이 든다면 참조 (boost::ref
또는 boost::cref
을 염두에 두어야 함)로 캡처하거나 원래 개체가 호출 지점에 존재하지 않으면 boost::shared_ptr
을 캡처하고 어댑터를 작성하십시오 메서드는 smartpointer를 언팩하고 someFunction
을 호출합니까?
편집 : 실험에서 boost::function
이 복사 될 때마다 해당 개체를 복사 할뿐만 아니라 boost::bind
안에 여러 번 복사합니다.
struct foo_bar {
std::vector<int> data; //possibly expensive to copy
foo_bar()
{ std::cout<<"default foo_bar "<<std::endl; }
foo_bar(const foo_bar& b):data(b.data)
{ std::cout<<"copy foo_bar "<<&b<<" to "<<this<<std::endl; }
foo_bar& operator=(const foo_bar& b) {
this->data = b.data;
std::cout<<"asign foo_bar "<<&b<<" to "<<this<<std::endl;
return *this;
}
~foo_bar(){}
};
void func(const foo_bar& bar) { std::cout<<"func"<<std::endl;}
int main(int, char*[]) {
foo_bar fb;
boost::function<void()> f1(boost::bind(func, fb));
std::cout<<"Bind finished"<<std::endl;
boost::function<void()> f2(f1);
std::cout<<"copy finished"<<std::endl;
f1();
f2();
return 0;
}
결과 출력은 다음에 같이 : I는 GCC 4.6 -O2 (및 -std = C++ 0X)로와 Mingw 32 따라 과급 1.45을 사용하여 다음과 같은 코드를 사용하여 테스트
default foo_bar
copy foo_bar 0x28ff00 to 0x28ff10
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff1c
copy foo_bar 0x28ff1c to 0x28ff34
copy foo_bar 0x28ff34 to 0x28fed4
copy foo_bar 0x28fed4 to 0x28fee4
copy foo_bar 0x28fee4 to 0x28fef4
copy foo_bar 0x28fef4 to 0x28fe14
copy foo_bar 0x28fe14 to 0x28fe24
copy foo_bar 0x28fe24 to 0x28fe34
copy foo_bar 0x28fe34 to 0x6a2c7c
Bind finished
copy foo_bar 0x6a2c7c to 0x6a2c94
copy finished
func
func
따라서 복사 생성자는 f1에 대한 바인딩 및 할당을 위해 f2를 한 번 및 11 번 생성하도록 호출되었습니다. 첫 번째 객체가 스택에 생성되고 사본의 주소가 그와 매우 비슷하고 약간 증가하기 때문에 바인딩 프로세스는 많은 경우에 사용됩니다.이 경우 컴파일러는 인라인하지 않으며 각 값에 따라 객체를 전달하십시오. 어디 그 결과를 저장하지 않고 단지 boost::bind
사용 :
int main(int, char*[]) {
foo_bar fb;
boost::function<void()> f1(boost::bind(func, fb));
return 0;
}
default foo_bar
copy foo_bar 0x28ff00 to 0x28ff10
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff1c
copy foo_bar 0x28ff1c to 0x28ff34
copy foo_bar 0x28ff34 to 0x28fef4
그래서 5 부를 그냥 객체를 바인딩합니다. 따라서 코드의 원격 성능에 민감한 부분이라 할지라도 가치 당 최소한의 복사 비용을 가진 것은 캡처하지 않는 것이 좋습니다. 비교 gccs에서 std::tr1::bind
와 std::bind
는 (코드가 제 testcode와 기본적으로 동일하다 (표준 : TR1 :: 기능/표준 : 기능과 관련하여) 더 나은 수행 단지 대체 boost::
std::
각각 std::tr1::
와 :
std::tr1::bind with std::tr1::function:
default foo_bar
copy foo_bar 0x28ff10 to 0x28ff28
copy foo_bar 0x28ff28 to 0x28ff34
copy foo_bar 0x28ff34 to 0x28ff04
copy foo_bar 0x28ff04 to 0x652c7c
Bind finished
copy foo_bar 0x652c7c to 0x652c94
copy finished
func
func
std::bind with std::function:
default foo_bar
copy foo_bar 0x28ff34 to 0x28ff28
copy foo_bar 0x28ff28 to 0x3c2c7c
Bind finished
copy foo_bar 0x3c2c7c to 0x3c2c94
copy finished
func
func
나는 std::bind
이 내부 호출에 대한 const ref를 전달하거나, gcc inliner에 더 친숙한 방식으로 작성되어 중복 된 복사본 생성자를 인라인하고 제거합니다. tr1::bind
은 여전히 최적 상태가 아니지만 여전히 boost::bind
으로 최적화되어 있습니다.
물론 이런 종류의 테스트를 통해 항상 다른 컴파일 플래그/컴파일러를 사용하는 YMMV
나오는 때 호출 내가 테스트 프로그램을 작성하고 당신이 함수 개체를 복사 할 때마다 호출되는 않는 저장된 객체의 복사 생성자처럼 보인다 . 또한 boost :: bind는 복사 생성자를 11 번 호출합니다! – Chris
@Chris : 알겠습니다. 그래서 제 테스트는 우연히 알게 된 것이 아닙니다. 그래서 사람이 C++ 11을 사용할 수 있다면 std :: bind는 먼 거리로 갈 수있는 방법입니다 (개인적으로는 lambdas를 대신 사용 하겠지만). – Grizzly