2013-07-02 41 views
19

我有以下代碼:的std ::綁定失去參考

#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); 
} 

,並將其輸出

1.000000 
2.000000 
2.000000 

這意味着該callback功能得到了t副本,而不是參考t。我想知道發生了什麼,因爲對於std::bind它應該是完美轉發。

回答

33

std::bind默認使用值語義。這是一個理智的默認設置,可以讓您安全地執行以下操作。

int f(double x); 

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

使用值語義是安全的:綁定參數的生命週期成爲bind返回的對象的生命週期。使用引用語義不會有保證。所以當你需要引用語義時,你需要明確;如果你遇到麻煩,那就是你的錯。爲了做到這一點,你需要使用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); 
} 

同樣的協議在標準庫中其他地方使用,像std::thread構造。

8

std::bind()是爲值語義設計的(as R. Martinho Fernandes nicely explains in his answer),而確實是在內部創建副本。你需要/想什麼是std::ref

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

std::ref返回一個std::reference_wrapper<>對象換到你原來的參數的引用。這樣,reference_wrapper周圍的對象t被複制,而不是t本身。

這允許您在值語義(默認假定)和引用語義(需要您明確的干預)之間進行選擇。

這是live example