Что происходит со значением, переданным в конструктор после того, как оно выпало из области видимости? - PullRequest
1 голос
/ 21 февраля 2011

Я искал ответ на этот вопрос и не нашел ничего похожего на мою проблему.

У меня есть класс, назовем его Foo, который принимает указатель const char* в своем конструкторе. В моем коде мне нужно создать новый Foo с std::string s .data() в качестве параметра. Проблема в том, что как только строка выходит из области видимости, значение (или указатель, вот где я запутался ..), переданное в Foo, становится недействительным.

Так что теперь, когда строка недействительна, Foo's const char* недействителен.

Как я могу передать значение данных строки в Foo, чтобы оно не стало недействительным, когда строка выпадает из области видимости?

Ответы [ 5 ]

4 голосов
/ 21 февраля 2011

Почему бы вам просто не сделать копию строки? Таким образом, вы знаете, что он не исчезнет. Если вы не знаете, что const char * будет существовать на протяжении всей жизни вашего класса, вам нужно скопировать его (или сделать что-то другое, например, обернуть строку в счетчик ссылок)

1 голос
/ 21 февраля 2011

У вас есть два варианта:

  1. (и, безусловно, более простой вариант) Просто сохраните его в std::string в вашем классе.
  2. Выделите свои char* с помощью new[] и strcpy данные в ваш новый char* в вашем конструкторе. Тогда вам также необходимо определить деструктор для delete[] Foo 's char*. Затем, как обычно в случае Правило трех , вам необходимо определить конструктор копирования и операторы копирования, а также назначить свои собственные новые char* (и в случае назначения копирования). оператор delete[] старый char*) и скопировать char* из оригинала Foo. Очень легко ошибиться и создать утечку памяти или случайный сбой при попытке доступа к освобожденной памяти.

х

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-символ.

1 голос
/ 21 февраля 2011

Вам, вероятно, следует скопировать строку в Foo, чтобы сохранить ее, если вам нужно, чтобы она прошла после области вызова конструктора.

0 голосов
/ 21 февраля 2011

Скопируйте это.На языке, дружественном к счетам, вы бы «сохранили» строку.Но это 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 вариант проще.

0 голосов
/ 21 февраля 2011

Простое описание не поможет понять, что происходит в вашем коде. 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 . Надеюсь, это поможет!

...