Pas vraiment une réponse, mais une correction à des années dirkgently qui ne rentrent pas dans un commentaire: vous ne devriez pas écrire tant le code comme il l'a fait.
La copie d'objets en toute sécurité n'est pas quelque chose que vous voulez vous tromper, bien que dans la vraie vie, la meilleure façon d'éviter cela est d'utiliser les classes de bibliothèques appropriées. Cela dit, une chaîne simple de style C est aussi bon exemple que toute autre chose à la pratique avec: « ne jette pas une exception »
class Book {
char *nm;
public:
Book(const char *name) : nm(copystr(name)) { /* don't throw an exception! */ }
Book(const Book &o) : nm(copystr(o.nm)) { /* Likewise! */ }
~Book() { delete[] nm; }
Book& operator=(const Book &o) {
// this is called copy-and-swap (CAS). If you absolutely
// have to write this kind of resource-managing code, then
// you will need this technique, because it's the best
// way to provide the strong exception guarantee.
Book cp = o;
swap(cp);
return *this;
}
/* or you can do this:
Book& operator=(Book cp) {
swap(cp);
return *this;
}
*/
void swap(Book &o) {
std::swap(this->nm, o.nm);
// also swap other members
}
};
char *copystr(const char *name) {
if (!name) return 0;
char *newname = new char[strlen(name)+1];
std::strcpy(newname, name);
return newname;
}
Voir la avertissement dans le constructeur? C'est parce que si vous le faites, la chaîne sera divulguée. Si vous avez besoin de plus d'une ressource dans votre classe qui nécessite une libération explicite, les choses deviennent vraiment fastidieuses. La bonne chose à faire est d'écrire une classe juste dans le but de maintenir la chaîne, et une autre dans le but de contenir l'autre ressource, et avoir un membre de chaque type dans votre classe Book. Ensuite, vous n'avez pas à vous soucier des exceptions dans le constructeur, car les membres qui ont été construits sont détruits si le corps du constructeur de la classe conteneur se déclenche. Une fois que vous avez fait cela à quelques reprises, vous serez très désireux d'utiliser les bibliothèques standard et TR1.
Normalement, pour sauver l'effort que vous souhaitez commencer en faisant votre classe non falsifiable, et seulement mettre en œuvre le constructeur de copie et l'opérateur = s'il se trouve que vous avez besoin:
class Book {
char *nm;
public:
Book(const char *name) : nm(copystr(name)) { }
~Book() { delete[] nm; }
private:
Book(const Book &o);
Book& operator=(const Book &o);
};
Quoi qu'il en soit, strdup
est pas grand mystère. Voici quelques implémentations très similaires (toutes deux de GNU), juste en cherchant "strdup.c". La même approche fonctionne généralement pour d'autres fonctions de gestion de chaînes et, en général, pour tout ce qui ne nécessite pas de mécanismes spécifiques à la plate-forme: recherchez "nom_fonction.c" et vous trouverez probablement une implémentation GNU expliquant comment cela fonctionne , et comment vous pouvez faire des choses similaires mais différentes. Dans ce cas, vous commencez avec leur code et remplacez l'appel par malloc
et la gestion des erreurs.
http://www.koders.com/c/fidF16762E3999BA95A0B5D87AECB0525BA67CEE45A.aspx
http://cvs.frodo.looijaard.name/viewvc/cgi-bin/viewvc.cgi/public/psiconv/compat/strdup.c?revision=1.1.1.1&view=markup
Généralement, vous utilisez 'std :: string' mais que voulez-vous dire par "sans utiliser la bibliothèque C++ STL"? c'est-à-dire quelles parties de la bibliothèque standard essayez-vous d'éviter (et pourquoi)? –
Pourquoi ne pouvez-vous pas utiliser 'strdup'? Vous demandez un outil pour faire quelque chose en refusant d'utiliser l'idéal. –
c'est une contrainte sur l'affectation ... peut-être que je devrais ajouter un tag de devoirs là ... et oui par STL je veux dire en utilisant la chaîne – aherlambang