Найдите и исправьте ошибки в приведённом C++ коде

Нужны delete[] для массивов, public-наследование, виртуальный деструктор Foo и глубокое копирование. Обычное копирование указателей приводит к общему владению одним буфером и двойному удалению.

Короткий ответ

Что ответить на собеседовании

Нужны delete[] для массивов, public-наследование, виртуальный деструктор Foo и глубокое копирование. Обычное копирование указателей приводит к общему владению одним буфером и двойному удалению.

Подробный разбор

Ответ с пояснениями

Условие

В этом фрагменте C++ кода есть проблемы, связанные с управлением динамической памятью и наследованием. Не меняя структуру классов, исправьте ошибки, чтобы программа корректно создавала, копировала и удаляла объекты.

class Foo
{
    public:
    Foo(int size) { i = new int[size]; }
    ~Foo() { delete i; }
    private:
    int* i;
};

class Bar : Foo
{
    public:
    Bar(int size) : Foo(size) { i = new char[size]; }
    ~Bar() { delete i; }
    private:
    char* i;
};

void main()
{
    Foo* f = new Foo(100);
    Foo* b = new Bar(200);
    *f = *b;
    delete f;
    delete b;
}

Ответ

Нужны delete[] для массивов, public-наследование, виртуальный деструктор Foo и глубокое копирование. Обычное копирование указателей приводит к общему владению одним буфером и двойному удалению.

Вариант с сохранением двух классов и их отдельных динамических массивов:

#include <algorithm>
#include <cstddef>
#include <memory>
#include <utility>

class Foo {
    std::size_t n;
    int* i;
protected:
    void swap(Foo& other) noexcept {
        std::swap(n, other.n);
        std::swap(i, other.i);
    }
public:
    explicit Foo(std::size_t size) : n(size), i(new int[n]{}) {}
    Foo(const Foo& other) : Foo(other.n) {
        std::copy_n(other.i, n, i);
    }
    Foo& operator=(Foo other) {
        swap(other);
        return *this;
    }
    virtual ~Foo() { delete[] i; }
};

class Bar : public Foo {
    std::size_t n;
    char* i;
    void swap(Bar& other) noexcept {
        Foo::swap(other);
        std::swap(n, other.n);
        std::swap(i, other.i);
    }
public:
    explicit Bar(std::size_t size)
        : Foo(size), n(size), i(new char[n]{}) {}
    Bar(const Bar& other)
        : Foo(other), n(other.n), i(new char[n]) {
        std::copy_n(other.i, n, i);
    }
    Bar& operator=(Bar other) {
        swap(other);
        return *this;
    }
    ~Bar() override { delete[] i; }
};

int main() {
    auto f = std::make_unique<Foo>(100);
    std::unique_ptr<Foo> b = std::make_unique<Bar>(200);
    *f = *b;
}

Размер хранится вместе с массивом; copy-and-swap не теряет прежний буфер, если создание копии не удалось. В main используется стандартная сигнатура int и RAII для самих объектов. *f = *b копирует только часть Foo, поскольку присваивание не полиморфно. Для копирования целого объекта неизвестного производного типа нужен отдельный контракт clone.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее