2016-10-06 6 views
4

Avant le 11 C++, j'ai vu code comme ceci:Faire une classe non copiable: méthodes non définies privées contre les méthodes supprimées

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

Pour 11 C++ (et versions ultérieures), je vois code comme cela:

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

Se comportent-ils de manière identique? Si non, veuillez expliquer.

Ref: https://ariya.io/2015/01/c-class-and-preventing-object-copy

Répondre

5

=delete donnera des messages d'erreur plus significatifs. Un message d'erreur sur une fonction supprimée vous indique qu'il n'existe pas et que personne ne peut créer un objet avec ce constructeur. Dire qu'il est privé ne donne pas cette information - il dit simplement que l'appelant ne peut pas l'appeler, pas que personne ne peut le faire.

En outre, un constructeur supprimé ne se comportera pas différemment s'il est appelé depuis l'intérieur/l'extérieur de la classe (puisque les constructeurs privés peuvent être appelés depuis la classe).

https://godbolt.org/g/06R9AQ

5

Ils sont similaires à bien des égards, mais diffèrent dans certains autres.

Tenir compte du code externe suivante en essayant de copier des objets de la classe:

int main() { 
    Car c; 
    Car other{c}; 
} 

Ces deux versions forcera le code ci-dessus à l'échec. À ce stade, cependant, le développeur regarderait l'interface pour voir pourquoi. Avec la version delete, il est évident que Car n'était pas destiné à être copié. Avec la version private, (au moins sans commentaire), cela soulève un doute quant à savoir si le constructeur de la copie a peut-être été placé dans la section private par accident.

Ne manquez membre Code d'essayer de copier des objets de la classe:

void Car::foo() { 
    Car c; 
    Car other{c}; 
} 

La version delete échoue comme avant. La version private est une erreur de liaison. Cela soulève un doute encore plus grand - il n'est pas rare d'oublier de définir une méthode qui a été déclarée. Peut-être que c'est ce qui est arrivé ici? La version delete n'a pas ce problème.

Modifier Scott Meyers discute ceci dans l'article 11 de Effective Modern C++fonctions supprimées à préfère les indéfinis privées.

+1

Bonne référence à l'article de Scott Meyers. Je l'ai découvert hier soir. – kevinarpe

3

Car& operator=(const Car&) = delete; exprime explicitement "affectation de copie interdite".

= delete; peut également être utilisé pour toute fonction comme décrit sur blog de Bjarne:

struct Z { 
    // ... 

    Z(long long);  // can initialize with an long long 
    Z(long) = delete; // but not anything less 
}; 
+0

Je n'étais pas au courant que delete peut être utilisé à d'autres fins. Excellent ajout. – kevinarpe

3

Notez que les deux extraits que vous posté donnent exactement la même erreur, qui est quelque chose comme:

' Car (const Car &) 'est privé dans ce contexte

Ceci est dû au fait que vous avez défini les méthodes de membre comme privées dans les deux cas.
Si vous voulez apprécier les différences, vous devriez plutôt avoir delete publique d constructeur de copie et opérateur copie, qui est la suivante:

class Car { 
public: 
    Car() {} 
// private: <-- this should not be here 
    Car(const Car&) = delete; 
    Car& operator=(const Car&) = delete; 
}; 

De cette façon, vous serez informé que ces méthodes membres ont été explicitement et intentionnellement supprimé:

utilisation de la fonction supprimé 'Car (const Car &)'

Les définir comme privés ne dit pas explicitement Je veux les supprimer.
Par exemple, cela aurait pu être fait pour que vous vouliez forcer les utilisateurs de votre classe à utiliser une méthode usine pour créer des instances de cette classe.

De toute façon, (ne plus ainsi) nouvelles fonctionnalités ne sont pas gratuites et leur utilisation d'une manière qui n'est pas l'intention ne donnera pas les avantages attendus.

+0

Bon point sur la publication de méthodes supprimées pour de meilleures erreurs de compilation! – kevinarpe

+0

@kevinarpe L'accessibilité est vérifiée avant tout. – skypjack