开发者

What is happening to the value passed into the constructor after it falls out of scope?

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..) passe开发者_StackOverflow中文版d 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?


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)


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


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.


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 !


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜