Деструктор C++ уничтожает объекты класса раньше, чем нужно

324
19 декабря 2016, 20:03

Добрый день!

Нужно создать класс (строка, завершающаяся терминальным нулём) и перегрузить операции «+» (конкатенация строк) и «[]» (вставка символа). С этими задачами я справился без труда, и пришло время заняться созданием деструктора. И тут понеслось...

Суть в том, что когда начинает работать процедура перегрузки операции «+», у меня создаётся дополнительная переменная k, в которую копируется первая строка, а затем при помощи strcat добавляется вторая. И, казалось бы, всё хорошо, но как только дело доходит до return, деструктор подчищает переменную k и возвращает... ну, возвращает всякую ерунду.

Не то чтобы я удивлён этим событием, я прекрасно понимаю, почему это происходит, но никак не могу решить эту проблему. Подскажите, как я могу исправить этот косяк.

Собственно говоря, код:

#define _CRT_SECURE_NO_WARNINGS
#include "stdafx.h"
#include <iostream>
#include <conio.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
class stroka
{
private:
    char* s;
    int n;
public:
    stroka();       //Конструктор по умолчанию
    stroka(int n1); //Конструктор с параметром
    void input();   //Функция ввода строки
    void output();  //Функция вывода строки на экран
    friend stroka& operator + (stroka& A, stroka& B);
    char& operator [] (int p)
    {
        return s[p];
    }
    ~stroka(void);
};
stroka::~stroka(void)
{
    std::cout << "Очистка памяти" << std::endl;
    delete[] s;
}
stroka::stroka()
{
    s = new char[1];
    *s = 0;
    n = 0;
}
stroka::stroka(int n1)
{
    s = new char[n1];
    n = n1;
}
void stroka::input()
{
    std::cout << "Введите строку: ";
    std::cin.getline(s, n, '\n');
}
void stroka::output()
{
    std::cout << "Введённая строка: " << s << std::endl << std::endl;
}
stroka& operator + (stroka& A, stroka& B)
{
    stroka k(A.n + B.n);
    strcpy(k.s, A.s);   //Копируем 1-ую строку в новую
    strcat(k.s, B.s);   //Вставляем 2-ую строку в конец новой
    return k;
}
int _tmain(int argc, _TCHAR* argv[])
{
    setlocale(0, "Rus");
    stroka A(10);
    stroka B(10);

    A.input();  //Ввод строки
    A.output(); //Вывод строки
    B.input();
    B.output();
    stroka C = A + B;
    C.output();

    int pos;    //Позиция вставки
    std::cout << "Номер позиции вставки элемента: ";
    std::cin >> pos;
    std::cout << "Введите элемент: ";
    char symbol;    //Вставляемый символ
    std::cin >> symbol;
    C[pos] = symbol;
    C.output();

    std::cout << endl << "Хорошего дня!";
    _getch();
    return 0;
}
Answer 1

Для начала, у вас неправильный оператор сложения. Он возвращает ссылку на экземпляр класса в стеке. Это плохо, потому что по выходу из функции его стек умирает. Переделайте функцию, чтобы она возвращала не ссылку, а копию объекта.

Далее, вам понадобится конструктор копирования (знаете, что это такое?). Дело в том, что при возвращении класса из функции локальная переменная копируется в результат при помощи этого самого конструктора. Поскольку у вас конструктор не определён, используется конструктор по умолчанию, который копирует все поля, в частности, "мёртвый" указатель.

Итого:

stroka operator + (const stroka& A, const stroka& B);
stroka(const stroka& A);

Кстати, правило «большой тройки» рекомендует сделать деструктор виртуальным, и добавить оператор присваивания.

READ ALSO
Обработка русского текста [дубликат]

Обработка русского текста [дубликат]

На данный вопрос уже ответили:

379
Почему округлятся переменная

Почему округлятся переменная

нахожу среднее арифметическое всех элементов двумерно массива но почему-то значение округлется, а мне нужно чтобы выдавало что то вроде...

330
Lint синтаксический анализатор

Lint синтаксический анализатор

нужно сгенерировать такую ошибку

337
Алгоритм Флойда-Уоршелла

Алгоритм Флойда-Уоршелла

У меня есть задание

415