I recently started to learn C++, and one of the tasks of my "self-made-up program for making things in language clear to me" is develop a class which will have functionality similar to Java strings. So, it should be something like immutable strings, i.e. when you make changes on such a string, it should not change its internal chars array, but instead return a modified copy of itself. It's pretty straightforward, but I encountered some undestanding problems regarding memory management. Things I already know about MM in C++:
- objects which were created on the stack are disposed when they go out of scope
- if an object is created in the heap (i.e. with newkeyword), it should be disposed manually withdelete(unless you use smart pointers.)
But if a class acts like immutable and, because of that fact, its objects implicitly create themselves sometimes, there are memory leak risks, as I can imagine. Here's an example (String is my educational class):
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
Some implemetation code (not including headers, etc.) is below. All questions asked can be read in comments.
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);
}
