【问题标题】:Copy const char*复制 const char*
【发布时间】:2011-01-18 06:23:56
【问题描述】:

我从函数接收一个 c 字符串作为参数,但我收到的参数将在稍后被销毁。所以我想复制它。

这就是我的意思:

class MyClass
{
private:
 const char *filename;

public:
 void func (const char *_filename);
}

void MyClass::func (const char *_filename)
{
 filename = _filename; //This isn't going to work
}

我想要实现的不是简单地将一个内存地址分配给另一个内存地址,而是复制内容。我希望文件名为“const char*”而不是“char*”。

我尝试使用 strcpy,但它要求目标字符串是非常量的。

有办法吗?没有在文件名上使用 const_cast 的东西?

谢谢。

【问题讨论】:

    标签: c++ string char


    【解决方案1】:

    [假设你继续以 C 风格实现你的类的内部,这在开发和执行速度方面可能有利也可能不利(取决于整个项目的设计),但通常不推荐赞成std::string 和朋友的。]

    转弯

    const char *filename;
    

    进入

    char *filename;
    

    strcpy 不会让你满意,因为你实际上需要一些内存来复制你的字符串 :)

    手动内存管理代码部分,请看 Tadeusz Kopec 的回答,好像没问题。

    另外,请记住两者之间存在差异

    const char *filename; // "filename" points to "const char" 
                          //  and is not const itself
    char const *filename; // semantically the same as above
    

    和

    char * const filename; // "filename" is const and points to "char", 
                           //  which is not const
    

    在第一种情况下,您可以使filename 指向任何其他const char 字符串,在第二种情况下,您只能“就地”更改该字符串(因此保持filename 值相同,如它指向相同的内存位置)。当然,如果需要,可以将这两个(或一个都不)结合起来。

    附:如果您将成员函数的参数命名为 _filename 只是为了避免与成员变量 filename 发生命名冲突,您可以在其前面加上 this(并去掉下划线):

    void MyClass::func (const char *filename)
    {
     ...
     this.filename = copy;
    }
    

    【讨论】:

    • ...不先分配内存?哎哟!
    • 好的,这可行。通过展示 C 的做事方式来为 C++ 提供案例总是很不错的! ;-)
    • Gahhh...没有提到释放析构函数中的内存?
    • @D.Shawley 这显然是由反对票驱动的答案,修复:))
    • @mlvljr Hehehe ...我忘了那些;)
    【解决方案2】:

    标准 C 库中有一个名为 _strdup 的函数(如果您想走 C 路线)。它使用 malloc 进行实际分配,因此您需要在使用完字符串后调用 free。

    例如,

    void MyClass::func (const char *_filename)
    {
        if (filename)
        {
            free(filename);
        }
        filename = _strdup(_filename);
    }
    

    当然,不要忘记释放析构函数中的文件名。

    【讨论】:

    • @Neil Butterworth 你又来了! :))
    • "strdup" 是 POSIX,正在被弃用。但是“_strdup”符合 ISO C++ 标准。
    【解决方案3】:

    我同意最好的办法(至少在不了解您的问题的情况下)是使用std::string。但是如果你坚持自己管理内存,你必须完全管理它。所以C++方式:

    class MyClass
    {
    private:
     const char *filename;
    
     MyClass(const MyClass&); // no implementation
     MyClass operator=(const MyClass &); // no implementation
    
    public:
     MyClass() {filename = 0;}
     ~MyClass() {delete[] filename;}
    
     void func (const char *_filename);
    }
    
    void MyClass::func (const char *_filename)
    {
     const size_t len = strlen(_filename);
     char * tmp_filename = new char[len + 1];
     strncpy(tmp_filename, _filename, len);
     tmp_filename[len] = '\0'; // I'm paranoid, maybe someone has changed something in _filename :-)
     delete[] filename;
     filename = tmp_filename;
    }
    

    和C方式

    class MyClass
    {
    private:
     const char *filename;
    
     MyClass(const MyClass&); // no implementation
     MyClass operator=(const MyClass &); // no implementation
    
    public:
     MyClass() {filename = 0;}
     ~MyClass() {free(filename);}
    
     void func (const char *_filename);
    }
    
    void MyClass::func (const char *_filename)
    {
     free(filename);
     filename = strdup(_filename); // easier than C++, isn't it?
    }
    

    【讨论】:

    • 你的类还需要一个拷贝构造函数和赋值运算符。
    • 谢谢。通过使 MyClass 不可复制来修复它:-)
    • //I'm paranoid, maybe someone has changed something in _filename :-) 一个邪恶的线程? :))
    【解决方案4】:

    为什么要把它当作 const,如果你需要在类的方法之一中改变它们。

    无论如何,非静态的 const 数据成员和引用数据成员不能被赋值;您应该使用带有构造函数的初始化列表来初始化它们。

    MyClass::MyClass(const char *_filename) : filename( _filename ) 
    { 
       // filename = _filename; This isn't going to work 
    }
    

    初始化器也可以调用如下函数

    MyClass::MyClass(const char *_filename) : filename( getfilename() ) 
    { 
       // filename = _filename; This isn't going to work 
    }
    

    没有验证这种特殊情况是最合适的,但初始化列表是将值分配给非静态 const 数据成员的方法。

    【讨论】:

      【解决方案5】:

      使用 std::string 复制值,因为您已经在使用 C++。如果您需要const char*,请使用c_str()。

      class MyClass
      {
      private:
          std::string filename;
      public:
          void setFilename(const char *source)
          {
              filename = std::string(source);
          }
      
          const char *getRawFileName() const
          {
              return filename.c_str();
          }
      }
      

      【讨论】:

      • 更好的是,使用隐式转换:filename = source;
      • 隐式转换永远不会“更好”。
      • 实际上不是转换,因为字符串 op= 为 char const* 重载,但仍然大约好 13 倍。
      • 嗯...filename.assign(source)?
      【解决方案6】:

      如果您想坚持使用纯 C,请使用 strncpy。但我同意 Ilya 的观点,使用 std::string 因为它已经是 C++。如果是您的应用程序调用了您的方法,您甚至可以首先收到一个 std::string,因为原始参数将被销毁。

      【讨论】:

        【解决方案7】:

        char const* 表示该类不拥有与其关联的内存。所有者总是需要一个非常量指针,否则无法释放内存。当您有非常量指针时,您可以为其分配内存,然后使用strcpy(或memcpy)复制字符串本身。但是,在您的情况下,使用 std::string 是一个更好的选择。

        【讨论】:

        • 不,这里的指针不是 const,memory 是。有一个指向char const 的指针非常好,你可以完全释放它的内存。
        • 即使指针是 const(如char* const),你也可以 delete[] 或 free() 它。
        • 术语 const 指针通常指的是“指向 const 的指针”,因为 const 值指针非常无用,因此很少使用。我更喜欢使用这个术语,尽管它有点模棱两可,因为替代方案(例如指向 const 的指针)很麻烦。
        • @Tronic:即使它是“指向 const 的指针”(例如 char const*),您也可以 delete[] 或 free() 它。 (free() 需要一个 const_cast,但这纯粹是由于 C 的遗留问题,正如 delete/delete[] 没有那个小问题所示。)我认为真正的问题是你试图暗示 const 的所有权,这不是你能做的。比较 string::c_str 并获取 vector::front 的地址(例如 &v.front() 或 &v[0]);有不同的 const ,但两块内存分别由 string 和 vector 拥有。
        • @Tronic:什么? free() 可以追溯到在 C 有 const 关键字之前,这就是我的意思。我认为您对 const 正确性感到困惑。销毁 const 对象很好,而且是必需的。注意这里的两个整数都被销毁了:int main() { int const* p = new int const(42); delete p; int const other = 42; }
        【解决方案8】:

        你必须决定你想要你的文件名是 const(所以它不能被改变)还是非常量(所以它可以在 MyClass::func 中被改变)。

        【讨论】:

          猜你喜欢
          • 2015-11-21
          • 1970-01-01
          • 2014-02-15
          • 1970-01-01
          • 2012-12-26
          • 2018-05-26
          • 2013-01-25
          • 1970-01-01
          • 2016-07-11
          相关资源
          最近更新 更多