Уничтожение объекта, создаваемого внутри функции перед его возвратом из функции
В попытке написать собственный класс 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 шт):
Проще показать, чем объяснять...
Вот ваш переделанный код, нормально работающий.
На ваше "Я создаю внутри оператора объект своего класса, пытаюсь присвоить ему определенные атрибуты, а компилятор создает объект, игнорирует ВСЮ ОСТАЛЬНУЮ часть кода, которая собственно за логику сложения и отвечает и просто возвращает мне пустой объект, как будто бы я написал две строчки, 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?