Переменная поля удалена перед вызовом фактического деструктора? - PullRequest
0 голосов
/ 10 января 2012

Что может сделать переменную поля устаревшей перед входом в деструктор при удалении объекта?Я искал ответ для этой проблемы, которую я имею на этом сайте, и наткнулся на это: Срок службы объекта закончился до вызова деструктора?

Что-то не складываетсявообще: если я объявил указатель на SomeClass внутри другого WrapperClass, когда я создаю WrapperClass, мне нужно создать new SomeClass и delete при уничтожении оболочки.Это имеет смысл и работает до сих пор.Указатель все еще действителен и корректен в деструкторе, иначе, очевидно, я не смог бы его удалить.

Теперь моя проблема в том, что мои члены поля (и int, и указатель на массив SomeClass) WrapperClass - это мусор, когда я вызываю деструктор.Я проверил объект-оболочку сразу после создания, и данные в порядке.Оболочка на самом деле является указателем в другом Main классе, и проблема возникает, когда я уничтожаю этот Main (который разрушает обертку), но работает нормально, если я просто delete обертка из другого метода в Main.Моя паранойя привела меня к вышеупомянутому ответу, и теперь я совершенно сбит с толку.Кто-нибудь хочет пролить свет на то, что на самом деле здесь происходит?

РЕДАКТИРОВАТЬ: Node это SomeClass.

class WrapperException{};
class Wrapper {
private:
    struct Node { /*....*/ };
    int numNodes;
    Node** nodes;
public:
    Wrapper() : numNodes(0) { nodes = new Node*[SIZE]; }
    Wrapper(const Wrapper& other) { throw WrapperException(); }
    Wrapper& operator=(const Wrapper& other) { throw WrapperException(); }
    ~Wrapper() { //calling delete Main gets me here with garbage for numNodes and nodes
        for(int i = 0; i < numNodes; i++)
            delete nodes[i];
        delete nodes;
    }
};

class MainException{};
class Main {
public:
    Main() { wrapper = new Wrapper(); }
    Main(const Main& other) { throw MainException(); }
    Main& operator=(const Main& other) { throw MainException(); }
    ~Main() { delete wrapper; }
private:
    Wrapper* wrapper;
};

Ответы [ 4 ]

2 голосов
/ 10 января 2012

Так как Гризли не отвечает, я отправлю это туда.

И вашему классу Main, и вашему классу Wrapper нужны правильно реализованные конструкторы копирования и операторы присваивания. См. Правило 3 .

Проблема в том, что если ваш класс когда-либо копируется (что легко сделать без вас, даже не подозревая об этом), то указатели копируются. Теперь у вас есть два объекта, указывающие на одно и то же место. Когда один из них выходит из области видимости, вызывается его деструктор, который вызывает delete для этого указателя, а указанный объект уничтожается. Затем другой объект остается с висящим указателем. Когда он уничтожается, он пытается снова вызвать delete для этого указателя.

2 голосов
/ 10 января 2012

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

class Wrapper {
private:
    struct Node { /*....*/ };
    int numNodes;
    std::vector<std::unique_ptr<Node>> nodes;
public:
    Wrapper() : numNodes(0) { nodes.resize(SIZE); }
    // No explicit destructor required
    // Correct copy semantics also implemented automatically
};

class Main {
public:
    Main() : wrapper(new Wrapper()) {}
    // Again, no explicit destructor required 
    // Copying banned for move-only class, so compiler tells you
    // if you try to copy it when you can't.
private:
    std::unique_ptr<Wrapper> wrapper;
};

Этот код гарантированно выполняется правильно. В C ++, если вы использовали new[], delete или delete[], немедленно выполните рефакторинг вашего кода, чтобы удалить их, и трижды проанализируйте любое использование без размещения new - создание unique_ptr довольно во многом единственный действительный случай. Это не что иное, как обычный ожидаемый результат ручного управления памятью.

0 голосов
/ 10 января 2012

Node** nodes;

должно быть

Node * nodes;

Также деструктор не так.Это должно быть:

for(int i = 0; i < numNodes; i++)
    delete nodes[i];
delete [] nodes;

Могут быть и другие проблемы, например, вы не создали конструктор копирования или оператор присваивания, чтобы можно было сделать так, чтобы копия объекта затем удаляла объект дляВы.

РЕДАКТИРОВАТЬ: изменил деструктор ...

0 голосов
/ 10 января 2012

Время жизни вашего объекта-оболочки закончилось, но целые и подобъекты-указатели, а также указатель все еще живы. Когда вы вызываете delete для указателя, время жизни pointee заканчивается, но указатель остается в живых. Время жизни указателя заканчивается после завершения вашего dtor.

Таким образом, если ваши члены испортились, то что-то еще происходит.

...