Правильный элемент данных для массива символов в классе

#c #memory-management #heap-memory

#c #управление памятью #куча-память

Вопрос:

Я реализую следующий класс в моем файле .hpp, используя метод OCF (ортодоксальная каноническая форма):

 class A {
    public:
        A(const char* theArray, size_t DefualtSize=0);
        ~A();
        Aamp; operator=(const char* anArray);
        
    protected:
        char *theArray;
    };
 

Этот класс будет работать, чтобы взять строку и сохранить ее в объекте «A» в куче. Реализация в моем файле .cpp выглядит следующим образом:

 A::A(const char* anArray, size_t DefaultSize) {
    char *theArray = new char[aDefaultSize];
    strncpy(theArray, anArray, DefaultSize);
};

A::~A() {
    delete[] theArray;
};
 

Мне было интересно, правильно ли я добавил элемент данных в класс, когда написал «protected: char * theArray;»? Должен ли я объявить элемент данных theArray как что-то другое / инициализировать его. Большое вам спасибо!

Комментарии:

1. На самом деле основная проблема заключается в том, что в вашем классе отсутствует конструктор копирования, что означает, что он не следует OCF (насколько я понимаю).

2. Извините за это, я только что добавил конструктор копирования, но забыл добавить его в свой исходный пост. Я также определил свой оператор присваивания после публикации.

3. В современном c использование необработанного указателя обычно является плохой практикой. Используйте интеллектуальные указатели вместо необработанных указателей. Используйте vector или deque вместо массива указателей, а string или любую другую строку impl вместо char*

Ответ №1:

Ваш код неверен, потому что вы повторно объявляете theArray

 A::A(const char* anArray, size_t DefaultSize) {
    char *theArray = new char[aDefaultSize]; // redeclaration here
    strncpy(theArray, anArray, DefaultSize);
};
 

лучше это

 A::A(const char* anArray, size_t DefaultSize) {
    theArray = new char[aDefaultSize];       // no redeclaration
    strncpy(theArray, anArray, DefaultSize);
};
 

В вашей версии вы объявили локальную переменную theArray в своем конструкторе, эта переменная скрывает переменную, объявленную в классе, поэтому ваш конструктор не инициализирует переменную класса.

Существуют и другие проблемы, strncpy сама по себе является проблемной функцией, поскольку она не гарантирует, что результирующий массив завершается нулем.

У вас есть дополнительный ; элемент в конце определения вашего конструктора

Ваш код не будет вести себя правильно, если new выдает исключение, потому что ваш деструктор попытается удалить неинициализированный указатель. Это лучше

 A::A(const char* anArray, size_t DefaultSize) : theArray(nullptr) {
    theArray = new char[aDefaultSize];
    strncpy(theArray, anArray, DefaultSize);
}
 

еще лучше это

 A::A(const char* anArray, size_t DefaultSize) : theArray(new char[aDefaultSize]) {
    strncpy(theArray, anArray, DefaultSize);
}
 

Комментарии:

1. Большое вам спасибо за ваши подробные ответы, Джон! Мне было интересно, после изменения «char * theArray» на просто «theArray» я получаю сообщение об ошибке «Нет соответствующей функции для вызова ‘strncpy'», что сбивает с толку, потому что я не изменил способ вызова функции. У вас случайно нет каких-либо указаний на то, как это исправить? Редактировать: я понял, что меняю защищенную переменную в своем классе на «const char * theArray», а объявление в фактическом использовании функции — «char * (something)», поэтому я изменил его обратно.

2. Это объясняет ошибку, const char* theArray в классе неверно, потому что он говорит theArray , что указатель нельзя использовать для изменения данных, на которые он указывает, но это именно то, что вы пытаетесь сделать при использовании strncpy .