2015-01-07 17 views
7

Le mie domande riguardano come restituire un oggetto che non ha un costruttore di copie. Ad esempio immaginiamo di avere un po 'di bigResource che si trova nell'heap, e diciamo che ne tengo traccia usando un unique_ptr. Supponiamo ora di dare la proprietà di questa risorsa a un bruco. Allora ho un CaterpillarWithBigResource. A un certo punto, questo CaterpillarWithBigResource diventerà un ButterflyWithBigResource, quindi l'oggetto Caterpillar dovrà trasferire la proprietà all'oggetto Butterfly.Come restituire un oggetto senza costruttore di copia

Ho scritto il seguente codice per modellare la situazione:

#include <cstdlib> 
#include <iostream> 
#include <memory> 

class ButterflyWithBigResource { 
public: 

    // If I uncomment just this line, I get an error 
    // ButterflyWithBigResource(const ButterflyWithBigResource& other) = default; 

    // If I uncomment just this line, I get an error 
    // ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete; 

    // With both above lines commented out, I get no errors, and the program runs fine. 

    ButterflyWithBigResource(std::unique_ptr<int>&& bigResource) : 
    bigResource(std::move(bigResource)) { 

    } 

    const int& getResource() { 
     return *bigResource; 
    } 

private: 
    std::unique_ptr<int> bigResource; 
}; 

class CaterpillarWithBigResource { 
public: 

    CaterpillarWithBigResource(int bigResource) : 
    bigResource(new int(bigResource)) { 

    } 

    ButterflyWithBigResource toButterfly() && { 
     return ButterflyWithBigResource(std::move(bigResource)); 
    } 
private: 
    std::unique_ptr<int> bigResource; 
}; 

/* 
* 
*/ 
int main(int argc, char** argv) { 
    CaterpillarWithBigResource caterpillarWithBigResource(5); 
    ButterflyWithBigResource butterflyWithBigResource(std::move(caterpillarWithBigResource).toButterfly()); 
    std::cout << butterflyWithBigResource.getResource() << std::endl; 
    return 0; 
} 

Si noti che né il Caterpillar né il Butterfly avere costruttori di copia predefinite, perché ognuno ha un unique_ptr. Tuttavia, non mi aspetto che questo sia un problema, quindi è necessario solo spostare i costruttori. Dopotutto, trasferisco solo la proprietà dallo Caterpillar allo Butterfly.

Infatti quando compilo il programma con g++ -c -g -std=c++11 -MMD -MP -MF utilizzando la versione g++4.8.2 funziona perfettamente.

Ma ora la cosa strana è che se ricordo il compilatore che i Butterfly 's costruttore di copia viene eliminato aggiungendo la riga ButterflyWithBigResource(const ButterflyWithBigResource& other) = delete;, il programma non viene compilato, e il compilatore si lamenta che costruttore di copia viene cancellato, in modo che io possa restituire Butterfly nel metodo toButterfly.

Se poi provo a dire che tutto è ok invece di avere la riga ButterflyWithBigResource(const ButterflyWithBigResource& other) = default;, ho di nuovo lo stesso errore.

Quello che voglio che accada è per il Butterfly costruito nel metodo toButterfly di essere spostati in toButterfly 'indirizzo di ritorno s, e poi utilizzato come argomento di Butterfly' costruttore mossa s quando si costruisce butterflyWithBigResource in main(). C'è un modo per farlo accadere?

+0

BTW, per restituire un oggetto senza costruttore di copia, utilizza copy- list-initialization: 'return {std :: move (bigRes ource)} ' – 0x499602D2

risposta

7

Quando si commentano sia le righe che esplicitamente lo default e il il costruttore di copie, il compilatore è libero di generare implicitamente un costruttore di spostamento (e spostare l'operatore di assegnazione).

In modo esplicito default ing oppure delete nel costruttore di copie, si sopprime la generazione implicita del costruttore di spostamenti.

Da N3337, §12.8/9[class.copy]

Se la definizione di una classe X non dichiara esplicitamente un costruttore mossa, uno sarà implicitamente dichiarato come default se e solo se
- X non ha un costruttore di copia user-dichiarato,
- ...

Quando il costruttore di spostamenti non viene più generato, il valore di ritorno da toButterfly() deve essere copiato, ma ciò non riesce a prescindere dal fatto che sia stato effettuato il default o eliminato il costruttore di copie.

Nel caso in cui si default il costruttore di copia, il compilatore è in grado di generare un'implementazione costruttore di copia di default a causa della presenza del membro di dati unique_ptr (che non è copiabile).

Quando si delete il costruttore di copie, se viene selezionato tramite la risoluzione di sovraccarico, si tratta di un errore.


Non si dovrebbe avere per eliminare in modo esplicito il costruttore di copia in quanto, come spiegato in precedenza, la presenza del membro di dati unique_ptr implicitamente lo elimina, ma se si vuole fare questo, allora avrete bisogno di anche predefinito esplicitamente il costruttore mossa (e l'operatore di assegnazione mossa troppo, se si vuole spostare l'assegnazione al lavoro)

ButterflyWithBigResource(ButterflyWithBigResource&&) = default; 
ButterflyWithBigResource& operator=(ButterflyWithBigResource&&) = default; 

Live demo

+0

oh ok è stato semplice. –

+0

Che risolto. Nel mio codice reale avevo 'virtuale ~ C() = default;'. –

+1

@NowIGetToLearnWhatAHeadIs * - '' X' non ha un distruttore dichiarato dall'utente * è il quarto punto elenco sopra :) – Praetorian

Problemi correlati