Не удается вернуть результат сложения строк
Результат метода успешно записывается в переменную, если верить отладчику, но при возвращении переменной данные теряются и возвращается случайный набор символов.
MyString& operator + (const MyString& other)
{
MyString result;
result.str = new char[strlen(this->str) + strlen(other.str) + 1];
for (int i = 0; i < strlen(str); i++)
result.str[i] = this->str[i];
for (int i = 0; i < strlen(other.str); i++)
result.str[i+strlen(this->str)] = other.str[i];
result.str[strlen(str) + strlen(other.str)] = '\0';
return result;
Уточняю код класса:
class MyString
{
public:
MyString()
{
str = nullptr;
size = 0;
}
MyString(const char* str)
{
size_t size = strlen(str);
this->str = new char[size+1];
for (int i = 0; i < size; i++)
{
this->str[i] = str[i];
}
this->str[size] = '\0';
}
~MyString()
{
delete[] this->str;
}
void Print()
{
cout << str;
}
MyString(const MyString& other)
{
size_t size = strlen(other.str);
this->str = new char[size + 1];
for (int i = 0; i < size; i++)
{
this->str[i] = other.str[i];
}
this->str[size] = '\0';
};
MyString& operator = (const MyString& other)
{
if (this->str != nullptr)
delete[] str;
size_t size = strlen(other.str);
this->str = new char[size + 1];
for (int i = 0; i < size; i++)
{
this->str[i] = other.str[i];
}
this->str[size] = '\0';
return *this;
};
MyString operator + (const MyString& other)
{
MyString result;
result.str = new char[strlen(this->str) + strlen(other.str) + 1];
for (int i = 0; i < strlen(str); i++)
result.str[i] = this->str[i];
for (int i = 0; i < strlen(other.str); i++)
result.str[i+strlen(this->str)] = other.str[i];
result.str[strlen(str) + strlen(other.str)] = '\0';
return result;
}
private:
char* str;
size_t size{};
};
Ответы (1 шт):
Нельзя возвращать из функций ссылки и указатели на временные объекты. При выходе из функции эти объекты удаляются и ссылка/указатель становятся невалидными.
//MyString& operator + () // неправильно
//MyString* operator + () // неправильно
MyString operator + () // правильно
{
MyString result; // локальная переменная с временем жизни внутри функции
....
return result;
} // при выходе из функции result уничтожается
Ещё хотелось бы увидеть код самого класса MyString.
Потому что вы выделяете память (ресурс) вне класса. Т.е. работа с памятью не инкапсулирована и скорее всего у вас утечка. Вы не поддерживаете идиому RAII в своем коде.
MyString result;
result.str = new char[strlen(this->str) + strlen(other.str) + 1]; // выделение памяти вручную вне класса
// А освобождение памяти вы сделали?
Сразу бросается в глаза - вы не следуете принципу DRY - Не повторяйся. У вас выделение памяти происходит во многих местах. Для избежания ошибок сделайте служебную функцию и выделяйте/перевыделяйте память в ней, например что-то типа allocate(). И её уже вызывайте в остальных методах.
Ещё одна типичная ошибка при работе с ресурсами - вы не сохраняете валидность объекта до конца операции. Всегда нужно учитывать, что при работе с ресурсами может произойти ошибка. В данном случае - ОС не смогла выделить память. В этом случае, объект который был должен сохраниться либо, перейти в другое, но тоже валидное состояние. Т.е. изначальная строка должна остаться как была, либо например стать пустой строкой.
MyString& operator = (const MyString& other)
{
if (this->str != nullptr)
delete[] str; // освободили память
this->str = new char[size + 1]; // а вот здесь произошла системная ошибка и память не выделилась
// в деструкторе вы попытаетесь повторно вызвать delete[] str;
// -------------------
// сохранить исходную строку:
{
char* tmpstr = new char[size + 1];
if(!tmpstr)
throw MemoryError(); // если память не выделилась - как-то прореагировать
if (this->str != nullptr)
delete[] str; // освободили память
str = tmpstr;
// -------------------
// строка становится пустой, но это тоже валидное состояние:
MyString& operator = (const MyString& other)
{
if (this->str != nullptr)
delete[] str; // освободили память
str = nullptr;
size = 0;
this->str = new char[size + 1];
if(!tmp.str)
throw MemoryError(); // если память не выделилась - как-то прореагировать
И вот эту всю логику лучше сделать в одном месте - в отдельной функции, чтобы в случае внесения изменений не искать по всему листингу все места, где вы выделяли память.