2015-01-29 13 views
8

Desidero memorizzare callback in un vettore o in un altro contenitore in C++ 11.Come archiviare la funzione std :: non copiabile in un contenitore?

Un modo per farlo sarebbe memorizzare un vettore di std :: function. Questo funziona bene per lambda o std :: bind con argomenti copiabili.

Tuttavia, se v'è una non copiabile (solo mobile) argomenti, viene sicuro a causa della conversione dalla lambda/std :: bind tipo interno alla std :: funzione ...

#include <vector> 

class NonCopyable { 
public: 
    NonCopyable() = default; 
    NonCopyable(const NonCopyable &) = delete; 
    NonCopyable(NonCopyable &&) = default; 
}; 

int main() { 
    std::vector<std::function<void()>> callbacks; 
    callbacks.emplace_back([] {}); 

    NonCopyable tmp; 
    callbacks.emplace_back(std::bind([](const NonCopyable &) {}, std::move(tmp))); 
    // When converting the object returned by std::bind to a std::function, 
    // a copy of the arguments happen so this code cannot compile. 
    return 0; 
} 

C'è un modo per spostare std :: bind argomenti nella funzione std :: invece di copiarli?

+2

'std :: function' richiede il functor che esso racchiude come CopyConstructible, quindi sei sfortunato. –

+0

Quindi c'è un modello migliore per memorizzare i callback? Ti piace packaged_task o un'altra classe? –

+0

Memorizza i puntatori alle funzioni o ai funtori, forse? – Cinch

risposta

5

std::ref e std::cref devono essere utilizzati in questo caso per evitare di copiare l'oggetto (vedere http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper).

Non sono sicuro che ho ottenuto il vostro domanda giusta, ma questo compila per me:

#include <vector> 
#include <functional> 

class NonCopyable { 
public: 
    NonCopyable() = default; 
    NonCopyable(const NonCopyable &) = delete; 
    NonCopyable(NonCopyable &&) = default; 
}; 

int main() { 
    std::vector<std::function<void()>> callbacks; 
    callbacks.emplace_back([] {}); 

    NonCopyable tmp; 
    auto fun = std::bind([](const NonCopyable &) {}, std::cref(tmp)); 
    callbacks.emplace_back(fun); 

    return 0; 
} 

EDIT: Come accennato nei commenti, fare attenzione al ciclo di vita della variabile di riferimento!

+1

Penso che voglia conservare il divertimento con il tmp e chiamare il divertimento più tardi. Il tuo codice può essere compilato, ma il tmp verrà liberato quando chiamerà il divertimento. Pensa a cambiare main() in add_callbacks() e chiama i callback in un'altra funzione. – alpha

+0

Sì, il tuo commento non è speciale per questo caso, ma è più un'affermazione generale sulle variabili che escono dal campo di applicazione :) – baol

0

È possibile utilizzare std::shared_ptr, che è possibile copiare. Qualcosa di simile

using ptr = std::shared_ptr<NonCopyable>; 
callbacks.emplace_back(std::bind([](const ptr &) {}, ptr(new NonCopyable()))); 

In questo modo oggetto NonCopyable volontà destruct auto on callback distruttore.

Problemi correlati