Not really an answer, but a correction to dirkgently's that won't fit in a comment: you really shouldn't write so much code as he did.
Safe object copying isn't something you want to get too badly wrong, although in real life the best way to avoid that is of course to use the appropriate library classes in the first place. That said, a simple C-style string is as good an example as anything else to practice with:
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;
}
See the "don't throw an exception!" warning in the constructor? That's because if you do, the string will be leaked. If you need more than one resource in your class that requires explicit freeing, that's when things become really tedious. The right thing to do is to write a class just for the purpose of holding the string, and another one for the purpose of holding the other resource, and have one member of each type in your Book class. Then you don't have to worry about exceptions in the constructor, because members which have been constructed are destructed if the constructor body of the containing class throws. Once you've done this a couple of times, you'll be pretty keen to use the standard libraries and TR1.
Normally, to save effort you'd start by making your class non-copyable, and only implement the copy constructor and operator= if it turns out you need them:
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);
};
Anyway, strdup
is no great mystery. Here are a couple of very similar implementations (both from GNU), just by searching for "strdup.c". The same approach usually works for other string-handling functions, and in general anything that doesn't require special platform-dependent mechanisms to implement: look for "function_name.c" and you'll probably find a GNU implementation that explains how it's done, and how you can do similar but different things. In this case you'd start with their code and replace the call to malloc
and the error-handling.
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