2013-07-02 36 views
19

Tôi có đoạn mã sau:std :: ràng buộc mất tài liệu tham khảo khi phân phối như tài liệu tham khảo rvalue

#include <stdio.h> 
#include <functional> 

template <typename T> 
auto callback(T&& func) ->decltype(func()) 
{ 
    return func(); 
} 

double test(double& value) 
{ 
    value=value+1.0; 
    return value; 
} 

int main(void) 
{ 
    double t=1.0; 
    printf("%f\n",t); 
    test(t); 
    printf("%f\n",t); 
    callback(std::bind(test,t)); 
    printf("%f\n",t); 
} 

Và nó ra

1.000000 
2.000000 
2.000000 

nào ngụ ý callback chức năng nhận được một bản sao của t thay vì một tham chiếu đến t. Tôi tự hỏi điều gì đã xảy ra, vì với std::bind nó sẽ là một sự chuyển tiếp hoàn hảo.

Trả lời

33

std::bind sử dụng ngữ nghĩa giá trị theo mặc định. Đó là một mặc định lành mạnh cho phép bạn làm những việc như sau một cách an toàn.

int f(double x); 

auto fun = std::bind(f, 1.0); // stores a copy, not a reference to a temporary 
fun(); 

Sử dụng ngữ nghĩa giá trị là an toàn: tuổi thọ của đối số bị ràng buộc trở thành tuổi thọ của đối tượng được trả về bởi ràng buộc. Sử dụng ngữ nghĩa tham chiếu sẽ không có đảm bảo đó. Vì vậy, bạn được yêu cầu phải rõ ràng khi bạn muốn ngữ nghĩa tham chiếu; nếu bạn gặp rắc rối thì đó là lỗi của bạn. Để làm được điều đó bạn cần phải sử dụng std::ref:

int main(void) 
{ 
    double t=1.0; 
    printf("%f\n",t); 
    test(t); 
    printf("%f\n",t); 
    callback(std::bind(test, std::ref(t))); 
    printf("%f\n",t); 
} 

giao thức này cũng được sử dụng ở những nơi khác trong thư viện chuẩn, giống như các nhà xây dựng std::thread.

8

std::bind() được thiết kế cho ngữ nghĩa giá trị (as R. Martinho Fernandes nicely explains in his answer) và làm tạo bản sao nội bộ. Những gì bạn cần/muốn là std::ref:

callback(std::bind(test, std::ref(t))); 
//      ^^^^^^^^^^^ 

std::ref trả về một đối tượng std::reference_wrapper<> bọc lấy một tài liệu tham khảo để lập luận ban đầu của bạn. Bằng cách này, đối tượng reference_wrapper xung quanh t được sao chép và không tự chụp t.

Điều này cho phép bạn chọn giữa ngữ nghĩa giá trị (giả định theo mặc định) và ngữ nghĩa tham chiếu (yêu cầu can thiệp rõ ràng của bạn).

Dưới đây là live example.

Các vấn đề liên quan