不是真正的答案,而是对不适合评论的 dirkgently 的更正:您真的不应该像他那样编写那么多代码。
安全对象复制不是您想犯的严重错误,尽管在现实生活中避免这种情况的最佳方法当然是首先使用适当的库类。也就是说,一个简单的 C 风格的字符串是一个很好的例子,可以用来练习:
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;
}
请参阅“不要抛出异常!” 构造函数中的警告?那是因为如果你这样做了,字符串就会被泄露。如果您的类中需要多个需要显式释放的资源,那么事情就会变得非常乏味。正确的做法是编写一个仅用于保存字符串的类,另一个用于保存其他资源的类,并在 Book 类中为每种类型都有一个成员。然后你不必担心构造函数中的异常,因为如果包含类的构造函数体抛出,已构造的成员将被破坏。一旦你这样做了几次,你就会非常热衷于使用标准库和 TR1。
通常,为了节省工作量,您首先要使您的类不可复制,并且仅在需要时才实现复制构造函数和 operator=:
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);
};
反正strdup
也不是什么大谜。这里有几个非常相似的实现(都来自 GNU),只需搜索“strdup.c”。相同的方法通常适用于其他字符串处理函数,并且通常任何不需要特殊平台相关机制来实现的东西:查找“function_name.c”,您可能会找到解释它是如何完成的 GNU 实现,以及如何做类似但不同的事情。在这种情况下,您将从他们的代码开始并替换调用malloc
和错误处理。
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