Загружаем изображение…
Глава 12. Классы и динамическое выделение памяти
При почленном копировании копируется указатель, а не данные, что ведёт к двойному освобождению (конструктор Text() создаёт объект, деструктор ~Text() уничтожает объект). Показано на картинке.

#include <iostream>
#include <cstring>
 
class Text {
private:
    char * data;
    int length;
public:
    Text(const char * str) {
        length = std::strlen(str);
        data = new char[length + 1]; //динамическая память new
        std::strcpy(data, str);
    }
    ~Text() {
        delete[] data;
    }
};
 
int main() {
    Text t1("Hello");
    Text t2 = t1;
    return 0;
}

 
Здесь возникнет ошибка – двойное удаление, так как указатель data у объектов t1 и t2 указывает на одну и туже ячейку памяти, при завершении у одного объекта уже адрес у указателя удален, а у второго объекта указатель продолжает указывать на ту ячейку памяти, но адрес уже удален и повторное удаление невозможно, так как ячейка памяти уже очищена. В таких случаях используется глубокое копирование.

#include <iostream>
#include <cstring>
class Text {
private:
    char * data;
    int length;
public:
    //Конструктор по умолчанию
    Text(const char * str) {
        length = strlen(str);
        data = new char[length + 1];
        strcpy(data, str);
        std::cout << "Default constructor, data: " << &data << std::endl;
    }
    //Конструктор копирвания
    Text(const Text & other) {
        length = other.length;
        data = new char[length + 1];
        std::strcpy(data, other.data
);
        std::cout << "Copy constructor, data: "<< &data << std::endl;
    }
    // Оператор=
    Text & operator=(const Text & other) {
        if (this == &other) return *this;
        delete[] data; // сначала очищаем указатель
        length = other.length;
        data = new char[length + 1]; //добавляем новый адрес
        std::strcpy(data, other.data
);
        std::cout << "Operator=, this data: "<< &data << std::endl;
        std::cout << "Operator=, other data: "<< &other.data << std::endl;
        return *this;
    }
   
    ~Text() {
        delete[] data;
    }
};
 
int main() {
    Text t1("Hello");
    std::cout << "============" << std::endl;
    Text t2 = t1;
    std::cout << "============" << std::endl;
    Text t3("Hi");
    std::cout << "============" << std::endl;
    t3 = t1;
   
    return 0;
}

Консоль:
Default constructor, data: 0xffffd4a86330
============
Copy constructor, data: 0xffffd4a86320
============
Default constructor, data: 0xffffd4a86310
============
Operator=, this data: 0xffffd4a86310
Operator=, other data: 0xffffd4a86330

Здесь добавился конструктор копирования (в отличие от конструктора по умолчанию можем заметить что принимает тип Text, а не const char *), перегруженный оператор присваивания (как раз-таки, когда у нас при двух созданных объектах один приравнивается к другому).
Специальные функции-члены, генерируемые компилятором
1. Автоматически создаются, если не определены:
2. Конструктор по умолчанию
3. Конструктор копирования
4. Операция присваивания
5. Деструктор
6. Операция взятия адреса
Конструктор копирования по умолчанию — почленное копирование (поверхностное).
Операция присваивания по умолчанию — почленное присваивание.
Просмотры: 18
Открыть в MAX Сообщить о неточности

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти