strdup的替代方案 我正在为一个包含名称:的书编写C++类。 class Book { private: char* nm; .......... ............ .......... ........... };

strdup的替代方案 我正在为一个包含名称:的书编写C++类。 class Book { private: char* nm; .......... ............ .......... ........... };,c++,string,dynamic-memory-allocation,strdup,C++,String,Dynamic Memory Allocation,Strdup,我不允许在此作业中使用std::string。因此,我在这里使用strdup将参数名的值复制到构造函数中的nm中: Book::Book(const char *name, int thickness, int weight) : nm(NULL) , thck(thickness) , wght(weight) { if (name) nm = strdup(name); } 是否有一种替代方法可以实现相同的结果而不使用strdup,而是使用关

我不允许在此作业中使用
std::string
。因此,我在这里使用
strdup
将参数名的值复制到构造函数中的nm中:

Book::Book(const char *name, int thickness, int weight)
    : nm(NULL)
    , thck(thickness)
    , wght(weight)
{
    if (name)
        nm = strdup(name);
}

是否有一种替代方法可以实现相同的结果而不使用strdup,而是使用关键字
new

严格地说:
string
类是Strings库的一部分。这更易于使用,本质上是动态的,并且在复制/赋值时,您比C样式的字符串更不用担心

另一种方法是手动复制:

class Book {
   public:
     Book(const char *name, ...) : nm(0), ... {
           if (!name) throw "invalid parameter";
           nm = new char [ strlen(name) + 1 ];
           strcpy(nm, name);
     }
     ~Book() {
           delete [] nm;
           // ...
     }
     Book(Book const& o) : nm(0), ... {
           if (!name) throw "invalid parameter";
           char *p = new char [ strlen(name) + 1 ];
           if (p) {
               strcpy(p, name);
               delete [] nm;
               nm = p; 
           }
     }
     Book& operator=(Book const& o) {
           if (this != &o) {
              char *p = new char [ strlen(name) + 1 ];
              if (p) {
               strcpy(p, name);
               delete [] nm;
               nm = p; 
              }
           }
           return *this;             
     }
 };

这种方法的问题是,您必须自己管理内存,并自己实现所有三大特殊成员函数(并尽可能确保异常安全)。

是的,还有其他选择。

  • 获取字符串的大小
  • 创建与字符串大小相同的数组
  • 将字符串的内容复制到该数组中
  • nm
    指向您分配的阵列

或者您可以使用
strdup
-顺便说一句,strdup不是
C++STL

的一部分,您必须使用strlen进行malloc,然后使用strcopy。愚蠢的家庭作业。顺便说一句。

不是一个真正的答案,而是对Dirkgenty的一个更正,它不适合在评论中:你真的不应该像他那样写那么多代码

Book::Book(const char *name, int thickness, int weight):nm(NULL), thck(thickness), wght(weight){ 
  if (name) {
     size_t length = strlen(name);
     nm = new char[length + 1];
     memcpy(nm, name, length + 1);
  }
安全对象复制并不是你想犯的严重错误,尽管在现实生活中,避免这种错误的最好方法当然是首先使用适当的库类。也就是说,一个简单的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

通常,为了省力,您首先要使类不可复制,并且只有在需要复制构造函数和运算符时才实现它们:

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
的调用和错误处理


通常你会使用<代码> STD::String 。但是“不使用C++ STL库”究竟意味着什么?i、 e.您试图避免使用标准库的哪些部分(以及为什么)?为什么不能直接使用
strdup
?你要求一个工具来做某事,而拒绝使用理想的工具。这是对作业的限制。。。也许我应该在那里加一个家庭作业标签。。。是的,通过STL,我的意思是使用StringProblem可能会有另一个标签
不是真正的问题
…这个任务必须是在strdup成为标准库的一部分之前首先构思的。当然,“如果不使用strdup,您将如何复制字符串?”的答案应该是“我为什么要这样做?”:)您不必在
new
之后检查
if(p)
,因为只有nothrow new可以返回空指针。您必须在
操作符=
中释放旧数组。复制和交换通常更好。是的,第二个是打字错误。我想用前者作为评论。(我假设OP在受限环境中工作,可能无法访问异常处理。)我认为delete p应该是delete[]nm。另外,不如使用set_string函数,而不是复制和粘贴代码。一旦设置了set_string,您可能会决定重用nm,如果它足够容纳下一个字符串,等等(而不是分配一个新字符串并丢弃旧字符串),然后最终意识到您需要一个字符串类,并编写一个。。。。。哦,等等……通过使用memcpyD'oh,您忘记了字符串末尾的null!谢谢-现在修好了。