Возвращение класса, который хранится в куче - PullRequest
1 голос
/ 06 октября 2011

У меня сбой из-за памяти в моем проекте.Мне удалось сократить его до следующего «игрушечного» проекта:

class Foo {
public:

    Foo() : bar(nullptr) {
        bar = new int(3);
    }

    ~Foo() {
        if (bar) {
            delete bar;
            bar = nullptr;
        }
    }

private:
    int* bar;
};

Foo test() {
    Foo foo;
    return foo;
}

int main() {
    test();
             // <--- Crash!
    return 0;
}

Я не могу понять, почему я проваливаюсь на указанной строке.Это то, что я собрал до сих пор, пожалуйста, исправьте меня, если я ошибаюсь:

По сути, я создаю foo в стеке в test().Foo выделяет некоторую память в куче.Все хорошо.Затем я пытаюсь вернуть foo.foo возвращается, но он немедленно уничтожается.Затем при выходе я снова пытаюсь уничтожить foo;и поэтому я дважды вызываю деструктор Foo, и я терплю крах.Я не понимаю, почему это проблема.Я проверяю, является ли Foo::bar нулевым, прежде чем удалять его, и, если я действительно удаляю его, я впоследствии устанавливаю его на ноль.

Почему это должно вызвать сбой?Как я могу это исправить?Что я делаю неправильно?Я весьма озадачен!: (

Обновление: главная причина, по которой это происходит, из-за отсутствия конструктора копирования, как указано в ответах ниже. Однако в моем исходном проекте действительно был конструктор копирования, или я так подумал.Если ваш класс является производным, вы должны явно создать конструктор копирования для производного класса. Base(const Derived& other) не считается конструктором копирования!

Ответы [ 2 ]

9 голосов
/ 06 октября 2011

Вы нарушили правило трех .

Когда вы вручную управляете памятью внутри вашего конструктора и деструктора, вы ДОЛЖНЫ также предоставить конструктор копирования и оператор присваивания, в противном случае ваша программа удалит память дважды и будет использовать память после удаления.

В вашем конкретном примере у вас есть конструктор копирования, предоставленный компилятором. Когда foo копируется в возвращаемое значение test, у вас есть два объекта с одинаковым указателем bar. Локальный foo выходит из области видимости и уничтожается, тогда его bar устанавливается на nullptr. Но копия, возвращаемое значение, все еще имеет ненулевой указатель. Затем он также уничтожается и снова удаляет ту же память.

2 голосов
/ 06 октября 2011

Вам необходимо реализовать конструктор копирования и, скорее всего, оператор присваивания.

Действительно, ваша проблема заключается в ручном управлении памятью.Это почти всегда ужасная идея, так как это один из самых распространенных способов появления ошибок в вашем коде.Используйте shared_ptr s вместо ручного управления памятью в вашем коде, и удивительно, насколько проще поддерживать ваш код!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...