2014-10-26 8 views
5

Ho scritto il seguente codice in cui provo a copiare il valore dell'oggetto unique_ptr in una struttura.Copia del valore di std :: unique_ptr tramite dereferencing

#include <iostream> 
#include <memory> 
using namespace std; 

struct S { 
    S(int X = 0, int Y = 0):x(X), y(Y){} 

    // S(const S&) {} 
    // S& operator=(const S&) { return *this; } 

    int x; 
    int y; 
    std::unique_ptr<S> ptr; 
}; 

int main() { 
    S s; 
    s.ptr = std::unique_ptr<S>(new S(1, 4)); 
    S p = *s.ptr; // Copy the pointer's value 
    return 0; 
} 

Si apre errori in Visual C++ 2012:

IntelliSense: nessuna conversione definita dall'utente adatto da "S" a "S" esiste
IntelliSense: nessun operatore "=" le partite questi operandi tipi operandi sono: std :: unique_ptr> = std :: unique_ptr>
errore C2248: 'std :: unique_ptr < _Ty> :: unique_ptr': non può accedere membro privato dichiarato nella classe 'std :: unique_ptr < _Ty>'

A meno che non annulli le righe in cui ho tentato di definire un costruttore di copia e un operatore. Questo elimina gli errori del compilatore ma non gli errori di IntelliSense. Si compila indipendentemente dagli errori di IntelliSense visualizzati nell'elenco degli errori.

Quindi, perché non è possibile utilizzare solo le funzioni predefinite e compilarle? Sto facendo la copia del valore nel modo giusto? Come dovrei definire il costruttore di copie se ne ha bisogno?

risposta

5

Il costruttore di copia non è implicitamente generare perché si ha un costruttore definito dall'utente, perché è il motivo per cui il tuo tentativo di copiare un S fallisce.

Ma ancora, unique_ptr non sono copiabile, solo mobile, in modo da poter utilizzare un mossa costruttore per S:

S(S&& other) : x(other.x), y(other.y), ptr(std::move(other.ptr)) 
{ 

} 

e chiamarlo:

S p = std::move(s); // Move s to p 

Live demo

+0

Non c'è davvero modo di copiare il valore del puntatore anche su un oggetto stack senza sacrificarlo? Con questo intendo di lasciare solo le informazioni 'ptr', e solo di copiare i valori di' x' e 'y'. – cpx

+0

@cpx L'intero punto di un 'unique_ptr' è che è univoco, quindi nessun altro oggetto può scrivere nella memoria del puntatore. Se vuoi che più di un oggetto faccia riferimento alla memoria, devi usare la classe appropriata, probabilmente un 'shared_ptr'. – IllusiveBrian

+0

È possibile copiare i dati indicati da 'unique_ptr' e inserire la build che copia all'interno di un nuovo' unique_ptr'. Direi che è perfettamente ragionevole anche. Il puntatore originale è ancora 'unico', ancora l'unico puntatore a quell'oggetto originale. Va bene avere un altro puntatore a un oggetto * diverso * con lo stesso valore. Per esempio. 'auto x1 = make_unique (7); auto x2 = make_unique (7); '** Ma **, porterà a slicing (e forse comportamento indefinito) se si tenta di copiare il valore in un' unique_ptr ' che in realtà sta puntando a un 'Derived'. (Ci sono anche soluzioni alternative.) –

2

std::unique_ptr non è né Copia Consegnabile né Copia Assegnabile.

Un operatore di assegnazione di copia implicita e costruttore per S si formerà male e quindi il messaggio di errore.

È possibile comunque utilizzare S p = std::move(s); come std::unique_ptr è spostare da costruzione sia Sposta assegnabili,

+0

Questa risposta è corretta, ma penso che l'impostazione circolare nella domanda. Il vero problema è che 'S' non è copiabile o copiabile. Il motivo 'S' è problematico perché ha un membro' unique_ptr '- il membro potrebbe essere' unique_ptr 'invece di' unique_ptr 'e causerebbe comunque lo stesso problema. –

2

Quindi, perché non è possibile utilizzare solo le funzioni predefinite e compilarle?

Per quanto comprendo, l'idea alla base unique_ptr contenitore è che gestisce solo la vita del suo contenuto (un puntatore a T), fino ad essere rilevati da tale imposta (usando swap o reset metodi), o avere distrutto efficacemente il suo contenuto (quando è esso stesso distrutto). La seconda proprietà importante di unique_ptr è che deve consentire tipi incompleti per T (in modo da supportare i puntatori opachi).Ciò significa che il valore contenuto potrebbe non essere CopyConstructible. Per questo motivo, unique_ptr non può essere CopyConstructible.

Sto facendo la copia del valore nel modo giusto? Come dovrei definire il costruttore di copie se ne ha bisogno?

Se T finisce per essere CopyConstructible, come si vuole farlo, è necessario gestire la copia a mano mediante l'accesso alla puntatore, come si sta facendo in main. Il costruttore di copie dovrebbe probabilmente fare la stessa cosa.

2

Non una risposta completa, solo informativo:

mi raccomando l'aggiunta di visibilità nella vostra esperimento:

std::ostream& 
operator<<(std::ostream& os, const S& s) 
{ 
    os << '{' << s.x << ", " << s.y << ", "; 
    if (s.ptr != nullptr) 
     os << s.ptr.get() << ':' << *s.ptr; 
    else 
     os << "nullptr"; 
    return os << '}'; 
} 

Ora si può dire cose come:

cout << "s = " << s << '\n'; 

in più punti il tuo esperimento e ottieni davvero una buona visuale su ciò che sta accadendo dopo ogni passaggio. Questo dovrebbe aiutarti ad analizzare e continuare nella tua progettazione.

Problemi correlati