2013-07-02 11 views
19

Ho il seguente codice:std :: bind perdere di riferimento al momento della consegna come riferimento 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); 
} 

Ed uscite

1.000000 
2.000000 
2.000000 

che implica la funzione callback ottenuto una copia di t invece di un riferimento a t. Mi chiedo cosa sia successo, dal momento che per il std::bind dovrebbe essere l'inoltro perfetto.

risposta

33

std::bind utilizza la semantica del valore per impostazione predefinita. È un predefinito sano che ti consente di fare cose come le seguenti in modo sicuro.

int f(double x); 

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

Utilizzando semantica di valore è sicuro: la durata degli argomenti legati diventa la durata dell'oggetto restituito da impegnare. L'utilizzo della semantica di riferimento non avrebbe questa garanzia. Quindi sei obbligato ad essere esplicito quando vuoi la semantica di riferimento; se ti metti nei guai, è colpa tua. Per fare questo è necessario utilizzare 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); 
} 

Questo stesso protocollo viene utilizzato in altre parti della libreria standard, come il costruttore std::thread.

8

std::bind() è progettato per semantica del valore (as R. Martinho Fernandes nicely explains in his answer) e fa crea copie internamente. Quello che vi serve/desiderare è std::ref:

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

std::ref restituisce un oggetto std::reference_wrapper<> che avvolge un riferimento al vostro argomento originale. In questo modo, l'oggetto reference_wrapper viene copiato e non lo è t stesso.

Ciò consente di scegliere tra semantica del valore (presupposta per impostazione predefinita) e semantica di riferimento (che richiede l'intervento esplicito).

Questo è un live example.