размещение, новое для подчинений другому конструктору

Действительно ли это безопасно? Я не использую виртуальных функций в своей фактической реализации, но я испытываю желание полагать, что, даже если бы я был, это все еще было бы безопасно.

class Foo
{
    Foo()
    {
        // initialize things
    }

    Foo( int )
    {
         new ( this ) Foo();
    }
}
11
задан Daniel Daranas 19 April 2010 в 14:32
поделиться

6 ответов

К тому времени, когда вы введете открытую фигурную скобку конструктора Foo (int) , у всех членов класса будет вызван их конструктор. Если вы затем принудительно вызовете другой конструктор с новым размещением, вы перезапишете текущее состояние класса. Это в основном означает, что у всех членов свои конструкторы вызываются дважды - если что-то делает new в своем конструкторе, вы пропускаете этот контент, и вы действительно, действительно, все испортите! Фактически вы создаете два объекта , и деструкторы для членов первого объекта никогда не вызываются , поскольку второй объект перезаписывает память первого объекта.

Другими словами, это ПЛОХО ! Не делай этого !!

Наиболее распространенный обходной путь - использовать какую-либо функцию инициализации и вызывать ее из обоих конструкторов. Однако это не позволит вам инициализировать члены const и другие, которые должны быть в списке инициализаторов.

13
ответ дан 3 December 2019 в 05:57
поделиться

Меня беспокоит то, что если Foo использует множественное наследование, вам нужно сначала привести указатель this к самому базовому классу. В противном случае, если this смещен (иногда случается при множественном наследовании), он будет построен по неправильному адресу.

1
ответ дан 3 December 2019 в 05:57
поделиться

Похоже, лучшее решение этой проблемы просто создать другую функцию для инициализации:

class Foo
{
    inline void nullify()
    {
        // initialize things
    }

    Foo()
    {
        nullify();
    }

    Foo( int )
    {
        nullify();
    }
}
1
ответ дан 3 December 2019 в 05:57
поделиться
​​

Вы не будете в безопасности, если расширите другой класс и у этого класса будет деструктор, например

class Foo
{
    int* a;
public:
    Foo():a(new int)
    {

    }
    ~Foo(){delete a;}
}

class Bar:public Foo
{
    Bar()
    {
        // initialize things
    }

    Bar( int )
    {
         new ( this ) Foo();
    }
}

First Bar (int) вызывает Foo () , затем вызывает Bar () , который также вызывает Foo () . При втором вызове Foo () он перезаписывает указатель, установленный первым вызовом Foo () , и происходит утечка выделенной памяти.

1
ответ дан 3 December 2019 в 05:57
поделиться

Ключевая проблема здесь в том, что конструкторы особенные - когда вы пишете конструкцию, которая вызывает конструктор (например, используйте ключевое слово new для создать объект) выполняется не только тело конструктора, вместо этого сначала строится вся цепочка объектов.

Таким образом, когда вы сначала используете синтаксис с новым размещением для запуска другого конструктора, C ++ автоматически повторно запускает все конструкторы объектов базового класса и все конструкторы переменных-членов, и только затем вызывается тело другого конструктора. Иногда с вами все будет в порядке, но много раз вы столкнетесь с неожиданным поведением.

1
ответ дан 3 December 2019 в 05:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: