Từ những gì tôi có thể tìm thấy (Đánh giá từ một đọc lướt qua các nguồn không chính xác đơn giản và một số thí nghiệm) nó sẽ sao chép các đối tượng nhân bản mỗi lần. Nó có thể là không cần thiết trong trường hợp hàm lấy đối số của nó bằng const &, nhưng nói chung đối tượng có thể bị đột biến bởi hàm. Nếu đối tượng là tốn kém để sao chép, nó sẽ không có ý nghĩa để nắm bắt nó bằng cách tham khảo (boost::ref
hoặc boost::cref
đến) hoặc, nếu đối tượng ban đầu không tồn tại tại thời điểm gọi, chụp boost::shared_ptr
và viết một bộ điều hợp phương pháp, trong đó unpacks các smartpointer và các cuộc gọi someFunction
?
Chỉnh sửa: Từ thử nghiệm không chỉ nó sẽ sao chép xây dựng đối tượng đó bất cứ khi nào boost::function
được sao chép, nhưng nó cũng sẽ sao chép nhiều lần bên trong boost::bind
. Tôi đã thử nghiệm bằng cách sử dụng đoạn mã sau sử dụng tăng 1,45 dưới mingw 32 với gcc 4.6 và -O2 (và -std = C++ 0x):
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;
}
Sản lượng kết quả được như sau:
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
Vì vậy, các nhà xây dựng bản sao được gọi là cho việc tạo ra các f2 một lần và 11 lần cho các ràng buộc và chuyển nhượng cho f1. Vì đối tượng đầu tiên được tạo trên ngăn xếp và địa chỉ của các bản sao rất gần và tăng nhẹ, có vẻ như quá trình liên kết đi qua rất nhiều hàm, trình biên dịch không trực tuyến trong trường hợp này và mỗi chuyển đối tượng theo giá trị. Chỉ sử dụng boost::bind
mà không lưu kết quả ở bất kỳ đâu:
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
Vì vậy, năm bản sao chỉ để ràng buộc đối tượng. Vì vậy, tôi thường sẽ tránh chụp bất kỳ thứ gì có ít nhất chi phí bản sao vừa phải cho mỗi giá trị trong bất kỳ bộ phận nhạy cảm hiệu suất từ xa nào của mã. Trong GCC so std::tr1::bind
và std::bind
thực hiện tốt hơn nhiều (kết hợp với std :: tr1 :: chức năng/std :: chức năng) (mã về cơ bản là giống với testcode đầu tiên, chỉ cần thay boost::
với std::tr1::
tương ứng std::
:
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
Tôi giả sử std::bind
hoặc chuyển qua const ref cho invocations nội bộ hoặc được viết theo cách thân thiện hơn với gccs inliner để nội tuyến một số và loại bỏ các nhà xây dựng sao chép dư thừa.
Tất nhiên là luôn luôn với một loại thử nghiệm YMMV với các biên dịch/biên dịch khác nhau
Tôi đã viết một chương trình thử nghiệm và có vẻ như các nhà xây dựng bản sao của đối tượng được lưu trữ không được gọi mỗi khi bạn sao chép các đối tượng chức năng . Ngoài ra, boost :: bind gọi hàm tạo bản sao 11 lần! – Chris
@ Chris: Ok, vì vậy bài kiểm tra của tôi không phải là một điều tốt để biết. Vì vậy, nếu người ta có thể sử dụng c + + 11 có vẻ như std :: bind là cách để đi bằng một lề xa (mặc dù cá nhân tôi sẽ chỉ sử dụng lambdas thay thế). – Grizzly