Я недавно начал изучать C ++, и одна из задач моей "самодельной программы для прояснения вещей на языке" заключается в разработке класса, который будет иметь функциональность, аналогичную Java строкам. Таким образом, это должно быть что-то вроде неизменяемой строки, то есть когда вы вносите изменения в такую строку, она не должна изменять свой внутренний массив chars, а вместо этого возвращает измененную копию самой себя. Это довольно просто, но я столкнулся с некоторыми нерешенными проблемами, связанными с управлением памятью. Вещи, которые я уже знаю о MM в C ++:
- объекты, которые были созданы в стеке, удаляются, когда они go выходят за рамки
- , если объект создается в куче ( т. е. с ключевым словом
new
, оно должно быть удалено вручную с помощью delete
(если вы не используете умные указатели.)
Но если класс действует как неизменяемый и, в силу этого факта, его объекты неявно создавая себя иногда, есть риски утечки памяти, как я могу себе представить. Вот пример (String
- мой учебный класс):
String *str1 = new String("str1"); // creating new object in the heap
String *str2 = new String("str2"); // another one
str1 = str2; // pointer to str1 object is lost, thereby it's memory leak
- or -
str1 += str2; // we haven't disposed old value of str1, now it's replaced by new object made of str1 + str2
Ниже приведен код реализации (не включая заголовки и т. Д. c.). Все задаваемые вопросы можно прочитать в комментариях.
String.h
class String {
public:
explicit String(const char *);
String operator+(String);
String operator+(String *);
String operator=(String);
String operator=(String *);
String operator+=(String);
String operator+=(String *);
/* . . . */
private:
String() = default;
String(String *, String *);
byte *_contents;
int _length;
String. cpp
String::String(const char *original) {
int len = std::strlen(original);
this->_contents = new byte[len + 1];
std::strcpy((char *)this->_contents, original);
this->_length = len;
}
String::String(String *first, String *second) {
/* not so important implementation details */
this->_contents = new byte[capacity + 1];
/* more of not so important implementation details*/
}
String String::operator+(String another) {
return operator+(&another);
}
String String::operator+(String *another) {
return String(this, another);
}
// clang warning: "operator =() should always return String&",
// and if I correct that, then it says this operator should return only *this. Why?
String String::operator=(String replacement) {
return operator=(&replacement);
}
String String::operator=(String *replacement) {
// I guess, now I should dispose internal array, because one object is replaced by another. Right?
// Or, maybe, it should be "delete(this)"?
delete[](this->_contents);
this->_contents = replacement->_contents;
this->_length = replacement->_length;
this->_isWide = replacement->_isWide;
return *this;
}
String String::operator+=(String addition) {
return operator+=(&addition);
}
String String::operator+=(String *addition) {
auto concatenated = new String(this, addition);
// Same question here as above.
delete[](this->_contents);
return operator=(concatenated);
}