Esplicitamente membro eliminato le funzioni in C++11, è ancora la pena di ereditare da una noncopyable classe base?

Esplicitamente membro eliminato le funzioni in C++11, è ancora la pena di ereditare da una noncopyable classe base?

Sto parlando del trucco in cui si privatamente ereditare una classe base che ha privato o eliminati costruttore di copia e copia di assegnazione (ad esempio boost::noncopyable).

Sono i vantaggi presentate in questo domanda ancora applicabile al C++11?


Non capisco perché alcune persone sostengono che è più facile fare una classe non copiabile in C++11.

In C++03:

private:
    MyClass(const MyClass&) {}
    MyClass& operator=(const MyClass&) {}

In C++11:

MyClass(const MyClass&) = delete;
MyClass& operator=(const MyClass&) = delete;

EDIT:

Come molti hanno sottolineato, e ‘ stato un errore quello di fornire vuoto corpi (cioè {}) per il privato costruttore di copia e l’operatore di assegnazione copia, perché consentirebbe la classe stessa richiamare gli operatori senza errori. Ho iniziato a non aggiungere il {}, ma ha funzionato in alcuni linker problemi che mi ha fatto aggiungere le {} per qualche futile motivo (non mi ricordo le circostanze). Conosco meglio. 🙂

  • Non stai descrivendo un idioma, ma solo una semplice implementazione. Il linguaggio rimane, ed è ora più semplice scrivere.
  • Come è più semplice che scrivere un vuoto privato costruttore di copia e copia privata operatore di assegnazione?
  • A cura di evitare l’uso improprio del termine ‘idioma’.
  • stackoverflow.com/a/7841332/576911
  • non si desidera che il {} C++03 esempio (che permette di copie entro funzioni membro).
  • “Non capisco perché alcune persone sostengono che è più facile fare una classe non copiabile in C++11.” Il tuo esempio mostra una ragione di ciò è semplice: hai il C++03 esempio sbagliato.
  • Io sono di solito preoccupati per gli utenti di una classe di copie, ma il punto è valido comunque.
  • ci possono essere momenti in cui si desidera essere in grado di copiare solo all’interno della classe, ma nella mia esperienza, la maggior parte del tempo quando si desidera non-semantica di copia, è perché non si fa mai senso per copiare. Detto questo, penso che eredita da un “effetto” mix-in classe è per il momento più leggibile rispetto all’utilizzo di = delete per me. Ho il sospetto che nel tempo il = delete metodo diventerà facilmente leggibile anche a me.
  • Se si pretende qualcosa è un idioma, non sei veramente libero di cambiare. R. Martinho Fernandes è proprio così, avete capito male, e non hai nemmeno conto di averlo fatto! Hai sparato te stesso in piedi. Il C++03 esempio è sicuramente non idiomatiche. È sempre un errore per una classe di essere pubblicamente non copiabile, ma privatamente copiabile con vuoto enti per il costruttore/operatore di assegnazione. Se c’è un caso d’angolo, che beneficeranno di questo malfunzionamento, è ancora un errore, anche se un architetturale.
  • Ouch! xkcd.com/386
  • Come, wow! 🙂 Altrimenti noto come la natura umana 🙂 Il linker “problemi” sono proprio il motivo per cui il C++11 è l’alternativa migliore. Si pensava che fosse un linker “problema”, ma il linker è stato di fatto impedisce la ripresa di te stesso in piedi! In C++03, questo idioma rende il linker report di errori nel codice per voi. In C++11, eliminando i costruttori rende il compilatore segnala l’errore. Come hai te indicato, non credo che il linker. Quindi hai aggiunto il vuoto definizioni. E hai il codice che in silenzio fa la cosa sbagliata. Hai appena risposto, per te. Con un po di aiuto:)
  • Penso che la risposta dovrebbe essere: C++11 è l’alternativa migliore a causa della natura umana, ecco perché. Perché gli esseri umani in questi giorni non so che cosa il linker non in modo che non la penso così, se un linker “viene visualizzato un errore” prenderanno la via di minore resistenza al silenzio. Facendo il loro codice non è sbagliato, errato cose. Voglio dire, l’uomo, io non credo che ci sia migliore argomento per il C++11 modo.

InformationsquelleAutor Emile Cormier | 2012-02-27



5 Replies
  1. 75

    Bene, questo:

    private:
        MyClass(const MyClass&) {}
        MyClass& operator=(const MyClass&) {}

    Ancora tecnicamente consente MyClass per essere copiato da soci e amici. Certo, i tipi e le funzioni sono teoricamente sotto il tuo controllo, ma la classe è ancora copiabile. Almeno con boost::noncopyable e = delete, nessuno possibile copiare la classe.


    Non capisco perché alcune persone sostengono che è più facile fare una classe non copiabile in C++11.

    Non è così tanto più “facile” come “più facilmente digeribile”.

    Considerare questo:

    class MyClass
    {
    private:
        MyClass(const MyClass&) {}
        MyClass& operator=(const MyClass&) {}
    };

    Se sei un programmatore C++ che ha letto un testo introduttivo, in C++, ma ha poca esposizione al idiomatiche C++ (ie: un sacco di programmatori C++), questo è… fonte di confusione. Dichiara costruttori di copia e copia operatori di assegnazione, ma sono vuote. Perché dichiarare a tutti? Sì, sono private, ma che solleva solo più domande: perché privati?

    Capire il perché di questo si impedisce la copia, è necessario rendersi conto che da dichiarazione di privati, è fare in modo che i non-soci/amici non possono copiare. Questo non è immediatamente evidente per i principianti. Né è il messaggio di errore che si ottiene quando si tenta di copiare.

    Ora, confrontare il C++11 versione:

    class MyClass
    {
    public:
        MyClass(const MyClass&) = delete;
        MyClass& operator=(const MyClass&) = delete;
    };

    Cosa ci vuole a capire che questa classe non può essere copiato? Niente di più che la comprensione di ciò che il = delete sintassi significa. Qualsiasi libro che spiega le regole di sintassi del C++11 vi dirà esattamente ciò che fa. L’effetto di questo codice è ovvio per un inesperto utente C++.

    Che cosa è grande circa questo idioma è che diventa un idioma perché è la più chiara, la più ovvia, modo di dire esattamente quello che vuoi dire.

    Anche boost::noncopyable richiede un po ‘ di più il pensiero. Sì, si chiama “noncopyable”, così si è autoesplicativo. Ma se non l’hai mai visto prima, si pone domande. Perché derivante da qualcosa che non può essere copiato? Perché i miei messaggi di errore parlare di boost::noncopyable‘s costruttore di copia? Ecc. Di nuovo, la comprensione del linguaggio richiede più sforzo mentale.

    • +1 mi piace come si illustrano che = delete non è necessariamente più facile da scrivere, ma più facile da leggere.
    • Voglio solo notare che il privato costruttore di copia e di operatori di assegnazione, senza definito corpo sarebbe fare il trucco. Si potrebbe dichiarare MyClass(const MyClass&); invece di fornire vuoto definizione MyClass(const MyClass&) {} e in questo modo la classe non è copia-costruibili dentro di sé. Tuttavia = delete rende programmatore intenzioni chiaro ed è auto-esplicativo.
  2. 24

    La prima cosa è che, come altri prima di me sottolineare il fatto che, ottenuto il linguaggio sbagliato, è dichiarare come privato e non definire:

    class noncopyable {
       noncopyable( noncopyable const & );
       noncopyable& operator=( noncopyable const & );
    };

    In cui il tipo di ritorno del operator= può essere praticamente qualsiasi cosa. A questo punto, se avete letto il codice intestazione, che cosa significa in concreto? Non possono essere copiati solo da amici o non può essere copiata di sempre? Si noti che se si fornisce una definizione come nel tuo esempio, si sta affermando che posso essere copiati solo all’interno della classe e con gli amici, è la mancanza di una definizione di che cosa si traduce questo in io non può essere copiato. Ma la mancanza di una definizione nell’intestazione non è sinonimo di mancanza di definizione ovunque, come potrebbe essere definita nel file cpp.

    Questo è dove ereditare da un tipo chiamato noncopyable rende esplicito che l’intenzione è quella di evitare di copie, nello stesso modo che se manualmente è scritto il codice di cui sopra si dovrebbe documento con un commento in linea che l’intenzione è la disattivazione di copie.

    C++11 non cambia nulla, si fa solo la documentazione esplicito nel codice. Nella stessa linea che si dichiara il costruttore di copia eliminati, si sono documentati che si desidera completamente disattivato,.

    Come un ultimo commento, la funzione in C++11 non basta essere in grado di scrivere noncopyable con meno codice o, meglio, ma piuttosto di inibire il compilatore di generare codice che non si desidera generare. Questo è solo un utilizzo di tale funzione.

    • Hai sollevato un punto molto importante:: il vuoto privato implementazioni non vi impedisce erroneamente copiato l’oggetto! L’idioma è non per fornire vuoto definizioni private. Il linguaggio è quello di fornire dichiarazioni solo.
    • questa soluzione non funziona con alcuni standard conforme compilatori/linker, in quanto richiedono che quando si dichiara una funzione membro è necessario anche definire. Per esempio, il Verde delle Colline del compilatore/linker non con un errore del linker per quanto riguarda mancanti definizioni per la vostra copia di un costruttore e un operatore di assegnazione, anche se il codice non li utilizza.
    • Interessante. Mi piacerebbe prendere in considerazione un compilatore/linker combo per essere rotto, in quanto c’è tutto maledettamente sacco di codice che utilizza questo linguaggio senza fornire definizioni. Tutto il toolkit Qt viene in mente.
    • La norma non richiedono definizioni per le entità che non sono odr-usato (in C++11 gergo, usato in C++98 gergo). Una toolchain che richiede la definizioni rifiuterebbe programmi corretti.
  3. 10

    Oltre ai punti di cui altri hanno portato fino…

    Con un privato costruttore di copia e l’operatore di assegnazione copia che non si definiscono impedisce a chiunque di fare copie. Tuttavia, se una funzione membro o un amico di funzione tenta di fare una copia, verrà visualizzato un link di errore di runtime. Se si tenta di fare in modo in cui si sono eliminati in modo esplicito tali funzioni, verrà visualizzato un errore di compilazione.

    Ho sempre il mio si verificano errori il più presto possibile. Fare errori di run-time avvenire presso il punto di errore invece di seguito (così fanno l’errore capita quando si modifica la variabile invece di quando l’avete letto). Fare tutti gli errori di runtime in fase di collegamento errori in modo che il codice non ha mai la possibilità di essere sbagliato. Rendere tutti i link di errori in fase di compilazione errori per accelerare lo sviluppo e che hanno un po ‘ più interessanti messaggi di errore.

  4. 5

    È più leggibile e consente al compilatore di dare il meglio di errori.

    L’ ‘cancellato’ è più chiaro al lettore, soprattutto se si sta sfiorando la classe. Allo stesso modo, il compilatore può dire che si sta tentando di copiare un non copiabile tipo, invece di dare un generico ‘cercando di accesso privata membro’ errore.

    Ma in realtà, è solo una caratteristica di praticità.

  5. 2

    Gente di qui, si consiglia di dichiarare le funzioni membro, senza definizione. Vorrei sottolineare che un tale approccio non è portatile. Alcuni compilatori/linker richiedono che, se si dichiara una funzione membro è inoltre necessario definire, anche se non è utilizzato. Se si utilizza solo il VC++, GCC, clang, allora si può ottenere via con questo, ma se si sta tentando di scrivere veramente portatile, codice poi alcuni altri compilatori (es. Verde delle Colline) avrà esito negativo.

    • Io sono scettico di questa risposta. Perché è legale per definire le funzioni membro di una classe in più unità di compilazione anzi, sarebbe difficile attuare questa anti-funzione. Esempio che funziona con gcc/clang/icc?

Lascia un commento