C ++ аспекты управления памятью для самодельных неизменяемых строк - PullRequest
0 голосов
/ 15 февраля 2020

Я недавно начал изучать 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);
}
...