Ссылка на неинициализированный объект iniside constructor - PullRequest
5 голосов
/ 22 октября 2010

Можно передать неинициализированный объект в родительский класс, как показано в следующем примере

class C
{
    public:
        C(int i): 
            m_i(i)
        {};

        int m_i;
}

class T
{
    public:
        T(C & c):
            m_c(c)
        {
        };

        C & m_c;
};


class ST : public T
{
    public:
        ST():
            T(m_ci),
            m_ci(999)
        {
        };

        C m_ci;
};

В конструкторе class T, c является ссылкой на неинициализированный объект.Если бы class T использовал объект c во время строительства, это могло бы привести к ошибке.Но так как это не так, это компилируется и работает нормально.Мой вопрос - это тормозит какую-то парадигму или хорошие директивы дизайна?Если да, то каковы альтернативы, потому что я нашел полезным выделить объект, требуемый родителем, в подклассе.

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

Ответы [ 3 ]

3 голосов
/ 22 октября 2010

Передача ссылки или указателя на что-то неинициализированное технически совершенно нормально.

Но причина, по которой вы спрашиваете, вероятно, заключается в том, что вы думаете, что что-то легко может пойти не так, что через некоторую цепочку вызовов можно случайно получить доступ к объекту до его инициализации. И я думаю, что это серьезная проблема. И есть еще одна вещь, которая может пойти не так, а именно то, что код в базовом классе T теперь может, возможно, сделать недействительным инвариант класса ST, напрямую изменив член данных ST instance ...

Итак, я думаю, что это немного рискованно.

Что касается порядка инициализации, C ++ основан на идее построения из частей вверх, в иерархии. Если конструктор выбрасывает, то полностью сконструированные вещи уничтожаются автоматически. Это было бы более сложно или менее эффективно с более произвольным порядком построения.

Приветствия & hth.,

2 голосов
/ 22 октября 2010

Я много видел это, и многие компиляторы будут предупреждать. Это нормально, если конструктор T никогда не разыменовывает ссылку c.

Если вы не хотите предупреждение, вам нужно сделать двухэтапное строительство. Создайте защищенный метод Init(C&) в T, а затем вызовите его в теле конструктора ST - к сожалению, m_c для этого потребуется указатель (поскольку ссылки не могут быть переназначены другому объекту)

1 голос
/ 22 октября 2010

Вы можете , но вы получаете неопределенное поведение.

В утилитах Boost вы найдете базовый от члена идиома , созданную R Самуэль Клатчко . По сути, вы делаете личную базу вместо частного члена. Эта база инициализируется первой, и вы можете использовать ее для других баз:

// ...

class C_base
{
public:
    C_base(int i) :
    m_ci(i)
    {}

    C m_ci;
};


class ST :
    private C_base
    public T
{
    public:
        ST() :
            C_base(999),
            T(m_ci),
        {
        };
};

Утилита Boost устраняет повторный код.

...