strdup的替代方案

时间:2010-03-14 22:35:28

标签: c++ string dynamic-memory-allocation strdup

我正在为包含名称的书编写C ++类:

class Book {
private:
    char* nm;
..........
............
..........
...........
};

我不允许在此作业中使用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代替?

5 个答案:

答案 0 :(得分:4)

不是一个真正的答案,而是一个不适合评论的改编:你真的不应该像他那样写出如此多的代码。

安全对象复制并不是你想要犯错的东西,尽管在现实生活中避免这种情况的最佳方法当然是首先使用适当的库类。也就是说,一个简单的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

答案 1 :(得分:3)

严格来说:string类是字符串库的一部分。这更容易使用,本质上是动态的,并且在复制/分配时比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;             
     }
 };

这种方法的问题在于你必须自己管理内存并自己实现所有Big-3特殊成员函数(并尽可能地确保异常安全)。

答案 2 :(得分:3)

是的还有替代方案。

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

或者您可以使用strdup - btw strdup不属于C++ STL

答案 3 :(得分:0)

你必须使用strlen malloc,然后使用strcopy。愚蠢的家庭作业btw。

答案 4 :(得分:0)

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);
  }