传递到构造函数的值超出范围后会发生什么情况?

发布于 2024-10-18 05:37:42 字数 371 浏览 2 评论 0原文

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

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

所以现在字符串无效,Foo 的 const char* 也无效。

如何将字符串数据的值传递到 Foo 中,以便在字符串超出范围时它不会变得无效?

I've been searching around for the answer to this and haven't found anything that was similar to my problem.

I have a class, let's call it Foo, that takes a const char* pointer in it's constructor. In my code, I need to create a new Foo with a std::string's .data() as the parameter. The problem is, once the string falls out of scope, the value (or pointer, this is where I'm getting confused..) passed to Foo becomes invalid.

So now that the string is invalid, the Foo's const char* is invalid.

How can I pass the value of the string's data into Foo so that it won't become invalid once the string falls out of scope?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

零度° 2024-10-25 05:37:42

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

Why don't you just make a copy of the string? That way you know it will not disappear. If you don't know the const char * is going to be around for the duration of your class's life you need to copy it (or do something different like have the string wrapped in a reference counter)

琉璃繁缕 2024-10-25 05:37:42

如果您需要将字符串保存到构造函数的调用范围之外,您可能应该将其复制到 Foo 中进行存储。

You should probably be copying the string inside Foo to store it if you need it to last past the constructor's calling scope.

魄砕の薆 2024-10-25 05:37:42

您有两个选择:(

  1. 也是迄今为止更简单的选择)只需将其存储在类中的 std::string 中即可。
  2. 使用 new[] 分配您自己的 char*,并将数据 strcpy 放入构造函数中的新 char* 中。然后,您还需要定义一个析构函数来删除 delete[] Foochar*。然后,就像通常的情况一样,三法则,您还需要定义复制构造函数和复制赋值运算符来分配它们自己的新 char* (在复制赋值运算符 delete[] 的情况下,旧的char*)并从原始 Foo 复制 char*。很容易犯错误并造成内存泄漏,或因尝试访问已释放的内存而随机崩溃。

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

我很有可能遗漏了一些东西,因为这超出了我的想象,但我相信有人会好心地在评论中指出这一点。

另外,使用 Boost 中的 shared_ptr 可能会让您的选项 #2 的生活更轻松,但我对此没有太多经验,而且对于一个小项目来说它可能有点繁重。

还有一条评论。您确实应该使用 string.c_str (与 string.data 相反,因为它添加了您需要的 NULL 字符。

You have two options:

  1. (and by far the easier option) Just store it in an std::string in your class.
  2. Allocate your own char* with new[], and strcpy the data into your new char* in your constructor. Then you'll also need to define a destructor to delete[] Foo's char*. Then, as is usually the case with the Rule of Three, you'll need to define copy constructor and copy assignment operators as well to allocate their own new char* (and in the case of the copy assignment operator delete[] the old char*) and copy the the char* from the original Foo. Very easy to make a mistake and create a memory leak, or random crashing from trying to access freed memory.

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

There's a good chance I left out something as this is off the top of my head, but I'm sure someone will be kind enough to point it out in the comments.

Also, using the shared_ptr from Boost may make your life easier for option #2, but I don't have much experience with it, and it might be a little heavy to use for just a small project.

And one more comment. You should really be using string.c_str as well (as opposed to string.data) as it adds the NULL character you'll need.

诗笺 2024-10-25 05:37:42

仅提供描述无助于破译代码中发生的错误。 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。希望这有帮助!

Just giving the description won't help to decipher what wrong is going on in your code. std::string::data() returns the pointer to the beginning character of the array of characters. As long as the memory location passed doesn't go invalid, both the class member and the passed parameter point to the same location. If you see that, the passed parameter goes out of scope( i.e., it is no more valid ) then your class member becomes a dangling pointer. In that case, better to do a copy of the passed string. This should give you an idea -

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

Output: I am a string
IdeOne. Hope this helps !

深府石板幽径 2024-10-25 05:37:42

复制它。在引用计数友好的语言中,您将“保留”字符串。但这是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 选项更容易。

Copy it. In a refcount friendly language you would "retain" the string. But this is C++. You have a high risk of dangling pointers if you do not copy it.

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

or

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

or

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

As you can see, the std::string option is easier.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文