1

我一直在寻找这个问题的答案,但没有找到任何与我的问题相似的东西。

我有一个类,我们称之为它Foo,它在它的构造函数中接受一个const char*指针。在我的代码中,我需要创建一个Foo以 a为参数std::string的新.data()参数。问题是,一旦字符串超出范围,传递给 Foo 的值(或指针,这是我感到困惑的地方......)变得无效。

所以现在字符串是无效的,Fooconst char*是无效的。

如何将字符串数据的值传递给Foo它,这样一旦字符串超出范围,它就不会变得无效?

4

5 回答 5

4

为什么不直接复制字符串?这样你就知道它不会消失。如果您不知道 const char * 将在您的班级生命期间存在,您需要复制它(或做一些不同的事情,例如将字符串包装在引用计数器中)

于 2011-02-21T00:17:13.680 回答
1

你有两个选择:

  1. (到目前为止更简单的选择)只需将其存储std::string在您的班级中。
  2. 将您自己char*new[], 和strcpy数据分配到您char*的构造函数中的 new 中。然后你还需要为delete[] Foo's定义一个析构函数char*。然后,与规则三的情况一样,您还需要定义复制构造函数和复制赋值运算符以分配它们自己的 new char*(在复制赋值运算符的情况下为delete[]old char*)并复制char*from原来的Foo。很容易出错并造成内存泄漏,或者由于尝试访问释放的内存而导致随机崩溃。

X

class Foo {
    char* x;
    Foo(const char* y) {
        copy(y);
    }
    Foo(const Foo &f) {
        copy(f.x);
    }
    Foo& operator= (const Foo f) {
        cleanup();
        copy(f.x);
    }
    ~Foo() {
        cleanup();
    }
    bool copy(const char* y) {
       int len = strlen(y);
       try {
           x = new char[len+1]; //+1 for NULL
       } catch (std::bad_alloc ex) {
           //log failure to allocate memory
           return false;
       }
       return true;
    }
    void cleanup() {
        if (x) {
            delete[] x;
        }
        x = NULL;
    }
};

我很有可能遗漏了一些东西,因为这不在我的脑海中,但我相信有人会在评论中指出这一点。

此外,使用shared_ptr来自 Boost 的选项可能会使您的选项 #2 更轻松,但我没有太多经验,仅用于一个小项目可能有点繁重。

还有一条评论。您真的应该使用string.c_str(而不是string.data),因为它添加了您需要的 NULL 字符。

于 2011-02-21T00:44:55.747 回答
1

Foo如果您需要它持续超过构造函数的调用范围,您可能应该复制其中的字符串以存储它。

于 2011-02-21T00:16:51.410 回答
0

复制它。在引用计数友好的语言中,您将“保留”字符串。但这是 C++。如果你不复制它,你就有很高的悬空指针风险。

class Foo
{
 public:
   Foo(const char*  _data) 
   { 
      mData = new char[strlen(_data) + 1];
      strcpy(mData, _data); 
   }
   Foo& operator=(const Foo& _other) { /* deep copy string */ } 
   Foo(const Foo& _other) { /* deep copy string */ }
   ~Foo() { delete[] mData; }
 private:
   char* mData;
};

或者

class Foo
{
 public:
   Foo(const char* _data) : mData(_data) { }
 private:
   std::string mData;
};

或者

class Foo
{
 public:
   Foo(const std::string& _data) : mData(_data) { }
 private:
   std::string mData;
};

如您所见,该std::string选项更容易。

于 2011-02-21T00:47:50.693 回答
0

仅提供描述无助于破译代码中发生的错误。std::string::data()返回指向字符数组的开始字符的指针。只要传递的内存位置不失效,类成员和传递的参数都指向同一个位置。如果您看到,传递的参数超出范围(即,它不再有效),那么您的类成员将成为一个悬空指针。在这种情况下,最好复制传递的字符串。这应该给你一个想法 -

#include <iostream>
#include <string>

class Foo
{
    const char* temp;

    public:
    Foo( const char* temp_ ) : temp(temp_) {}
    void check( )
    {
            while( *temp != '\0' ){
                std::cout << *temp ;
                ++temp;
            }
            std::cout << std::endl;
    }
};

int main()
{
    std::string str = "I am a string";

    Foo *obj = new Foo( str.data() );

    obj->check();
    return 0;
}

输出:我是一个字符串
IdeOne。希望这可以帮助 !

于 2011-02-21T00:31:21.820 回答