Оператор new разрушает инициализированные объекты после исключения? - PullRequest
1 голос
/ 04 декабря 2011

У меня есть класс A, который выделяет память в своем конструкторе, используя new.Что происходит, когда я выделяю блок A с и (в то время как new[] инициализирует одиночные A с) один из них выбрасывает std::bad_alloc в своем конструкторе?

Разрушает ли operator new[]уже инициализированные объекты?Или я обязан убедиться, что конструктор не выдает?

РЕДАКТИРОВАТЬ : два вызова new могут показаться запутанными, поэтому вот фрагмент кода для пояснения:

class A
{
    int* mem;
public:
    A()
    {
        try
        {
            mem = new int[3];
        }
        catch(bad_alloc&)
        {
            throw 5;
        }
    }
    ~A()
    {
        delete[] mem;
    }
}

A* list = 0;

try
{
    list = new A[50000];
}
catch(int)
{
    // When I get here, did the new[] above call the destructors
    // of all the objects it managed to construct before one of them threw?
}

Ответы [ 4 ]

3 голосов
/ 04 декабря 2011

Если вы выполните new Foo(), а конструктор Foo сгенерирует, то память, выделенная соответствующим operator new, будет освобождена. И если конструктор для любого члена Foo завершился успешно, будет вызван деструктор этого члена.

Если вы выполните new Foo[100], а 42-й конструктор сгенерирует, то все уже построенные объекты Foo будут уничтожены (в обратном порядке).

1 голос
/ 04 декабря 2011

Да, любые уже выделенные объекты будут удалены. Почему бы не попробовать сами?

#include <iostream>
#include <stdexcept>

class A {
    static int n;
public:
    A()
    {
        ++n;
        std::cout << "construncting A no. " << n << "...";
        // let's pretend we allocate something here
        // with new and it fails
        if (n == 5) {
            std::cout << std::endl;
            throw std::bad_alloc();
        }
        std::cout << "done\n";
    }
    ~A()
    {
        --n;
        std::cout << "destructed A no. " << n << "\n";
    }
};

int A::n = 0;

int main()
{
    try {
        A* a = new A[10];
    }
    catch (std::bad_alloc& e) {
        std::cout << "caught an exception!\n";
    }
}

Однако деструктор экземпляра, который выкинул конструктор, НЕ будет вызван (это можно увидеть, если запустить код выше). Тем не менее, элементы, которые были построены к этому моменту, будут удалены. Например, если этот конструктор выдает:

class foo {
    int i;
    bar* b;
public:
    foo() : i(42), b(new bar)
    {
        float f = 3.14;
        // something throws an exception here
    }
    ~foo()
    {
        delete b;
    }
};

i, b и f будут удалены, однако выделенная память не будет освобождена (delete b не вызывается), и у вас будет утечка памяти (использование умных указателей приведет к легко решить это).

Посмотрите на C ++ FaqLite для получения дополнительной информации об этом:

http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.10

http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.8

0 голосов
/ 04 декабря 2011

Если некоторые поля были успешно инициализированы их конструкторами, деструкторы будут вызываться автоматически.

0 голосов
/ 04 декабря 2011

Члены будут уничтожены.Переменные автоматической длительности в конструкторе выйдут из области видимости и будут должным образом уничтожены.

...