No es realmente una respuesta, pero una corrección a dirkgently de que no caben en un comentario: que realmente no debería escribir tanto código como lo hizo.
La copia segura de objetos no es algo que desee obtener demasiado mal, aunque en la vida real la mejor manera de evitar eso es, por supuesto, utilizar las clases de biblioteca apropiadas en primer lugar. Dicho esto, un simple cadena tipo C es un ejemplo tan bueno como cualquier otra cosa a la práctica con: "! No lanzan una excepción"
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;
}
Véase el advertencia en el constructor? Eso es porque si lo haces, la cadena se filtrará. Si necesita más de un recurso en su clase que requiera una liberación explícita, es cuando las cosas se vuelven realmente tediosas. Lo correcto es escribir una clase con el único propósito de mantener la cadena, y otra con el propósito de contener el otro recurso, y tener un miembro de cada tipo en su clase de Libro. Entonces no tiene que preocuparse por las excepciones en el constructor, porque los miembros que se han construido se destruyen si el cuerpo constructor de la clase contenedora lo arroja. Una vez que haya hecho esto un par de veces, tendrá muchas ganas de usar las bibliotecas estándar y TR1.
Normalmente, para ahorrar esfuerzo empezarías al hacer que su clase no copiable, y sólo implementar el constructor de copia y el operador = si resulta que usted los necesita:
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);
};
De todos modos, no es strdup
gran misterio Aquí hay un par de implementaciones muy similares (ambas de GNU), simplemente buscando "strdup.c". El mismo enfoque generalmente funciona para otras funciones de manejo de cadenas, y en general para cualquier cosa que no requiera mecanismos especiales dependientes de la plataforma para implementar: busque "nombre_función.c" y probablemente encontrará una implementación de GNU que explique cómo se hace. y cómo puedes hacer cosas similares pero diferentes. En este caso, comenzaría con su código y reemplazaría la llamada al malloc
y el manejo de errores.
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
lo general, se podría usar 'std :: string' pero lo que es exactamente lo que quiere decir con "sin usar la biblioteca STL C++"? es decir, ¿qué partes de la biblioteca estándar está tratando de evitar (y por qué)? –
¿Por qué no puedes simplemente usar 'strdup'? Estás pidiendo una herramienta para hacer algo mientras te niegas a usar la ideal. –
es una restricción en la tarea ... tal vez debería agregar una etiqueta de tarea allí ... y sí por STL me refiero al uso de la cadena – aherlambang