#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
.