首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >strdup的替代方案

strdup的替代方案
EN

Stack Overflow用户
提问于 2010-03-15 06:35:28
回答 5查看 14.7K关注 0票数 6

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

代码语言:javascript
复制
class Book {
private:
    char* nm;
..........
............
..........
...........
};

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

代码语言:javascript
复制
Book::Book(const char *name, int thickness, int weight)
    : nm(NULL)
    , thck(thickness)
    , wght(weight)
{
    if (name)
        nm = strdup(name);
}

有没有另一种方法可以不使用strdup而使用关键字new来实现相同的结果?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-03-15 06:39:46

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

另一种方法是手动复制:

代码语言:javascript
复制
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;             
     }
 };

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

票数 5
EN

Stack Overflow用户

发布于 2010-03-15 07:29:55

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

尽管在现实生活中避免这种情况的最好方法当然是首先使用适当的库类,但安全的对象复制并不是你想要犯的错误。也就是说,一个简单的C样式字符串是一个很好的示例,就像练习其他任何东西一样:

代码语言:javascript
复制
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=:

代码语言:javascript
复制
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

票数 4
EN

Stack Overflow用户

发布于 2010-03-15 06:42:37

是的,还有另一种选择。

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

或者你可以使用strdup -顺便说一下,strdup不是C++ STL的一部分。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2444085

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档