Уничтожение объекта, создаваемого внутри функции перед его возвратом из функции

В попытке написать собственный класс string с реализованной конкатенацией и возвратом длины строки, столкнулся со следующей проблемой: вроде бы перегрузил оператор сложения, который создает внутри себя новый объект моего класса, но с соединенными строками и возвращает ссылку на него, однако создавая в коде три объекта и присваивая третьему сумму предыдущих я ловил ошибку с кучей. Потыкав в отладчике я понял, что проблема заключается в том, что перед тем как возвратить объект (ну или же ссылку на него, от этого ничего не меняется) из перегруженного оператора, компилятор вызывает деструктор и уничтожает его. Естественно, что уже в конце для него деструктор будет вызываться второй раз, что и приводит к ошибке. Полазив в гугле я пришел к выводу, что мне при реализации оператора присваивания обязательно нужно реализовывать конструктор копирования, однако это ничего не поменяло. Почему же так происходит и как с этим бороться?

#include <iostream>
using namespace std;

class String
{
public:

    String()
    {
        str = nullptr;
        length = 0;
    }

    String(const char* str)
    {
        this->length = strlen(str);
        this->str = new char[length + 1];

        for (int i = 0; i < length; i++)
        {
            this->str[i] = str[i];
        }

        this->str[length] = '\0';
    }

    ~String()
    {
        delete[] str;
    }

    String(const String& other)
    {
        if (this->str != nullptr)
        {
            delete[] this->str;
        }

        this->length = other.length;
        this->str = new char[length + 1];

        for (int i = 0; i < length; i++)
        {
            this->str[i] = other.str[i];
        }

        this->str[length + 1] = '\0';
    }

    String& operator =(const String& other)
    {
        if (this->str != nullptr)
        {
            delete[] this->str;
        }

        this->length = other.length;
        this->str = new char[length + 1];

        for (int i = 0; i < length; i++)
        {
            this->str[i] = other.str[i];
        }

        this->str[length + 1] = '\0';

        return *this;
    }

    String& operator +(const String& other)
    {
        String new_str;
        new_str.length = this->length + other.length;
        new_str.str = new char[new_str.length + 1];

        for (int i = 0; i < this->length; i++)
        {
            new_str.str[i] = this->str[i];
        }

        for (int i = this->length, j = 0; i < new_str.length; i++, j++)
        {
            new_str.str[i] = other.str[j];
        }

        new_str.str[new_str.length] = '\0';

        return new_str;
    }

    int len()
    {
        return length;
    }

private:
    char* str; 
    int length;
};

int main()
{
    setlocale(LC_ALL, "rus");

    String a = "str1";
    String b = "str2";
    String result = a + b;

    return 0;
}

Ответы (1 шт):

Автор решения: Harry

Проще показать, чем объяснять...

Вот ваш переделанный код, нормально работающий.

На ваше "Я создаю внутри оператора объект своего класса, пытаюсь присвоить ему определенные атрибуты, а компилятор создает объект, игнорирует ВСЮ ОСТАЛЬНУЮ часть кода, которая собственно за логику сложения и отвечает и просто возвращает мне пустой объект, как будто бы я написал две строчки, String new_str и return new_str." — простите уж, значит, вы ухитрились и тут ошибок наделать. Я же не вижу, что вы там пишете...

#include <iostream>
using namespace std;

class String
{
public:

    String(const char * s = nullptr)
    {
        if (s == nullptr) s = "";

        length = strlen(s);
        str = new char[length + 1];
        strcpy(str,s);
    }

    ~String()
    {
        delete[] str;
    }

    String(const String& other):String(other.str)
    {
    }

    String& operator =(const String& other)
    {
        String tmp(other);
        ::swap(length,tmp.length);
        ::swap(str,tmp.str);
        return *this;
    }

    String operator + (const String& other)
    {
        char * buf = new char[length + other.length + 1];
        strcpy(buf,str);
        strcat(buf,other.str);
        return String(buf);
    }

    size_t len()
    {
        return length;
    }

    friend ostream& operator << (ostream& os, const String& s)
    {
        return os << s.str;
    }


private:
    char* str; 
    size_t length;
};


int main()
{

    String a = "str1";
    String b = "str2";
    String result = a + b;

    cout << result;

}

Кстати, не нравится мне ваш выбор хранения по умолчанию nullptr. Я от него отказался. Резко усложняет код — все время надо проверять указатель и ветвить... Во-вторых, как вы с вашим интерфейсом класса отличите пустую строку String (содержащую "") от nullptr?

→ Ссылка