Подтвердить что ты не робот

Инициализировать ссылку - предупреждение C4355: 'this': используется в списке инициализаторов базового элемента

class A;

class B {
public:
    B(A& a) : a(a) {}
private:
    A& a;
};

/* Method 1 */
/* warning C4355: 'this' : used in base member initializer list */
/*
class A {
public:
    A() : b(*this) {}

private:
    B b;
};
*/

/* Method 2 */
/* But I need to manually perform memory dellocation. */
class A {
public:
    A() { b = new B(*this); }
    ~A() { delete b; }

private:
    B* b;
};

int main() {
}

В настоящее время, когда я пытаюсь инициализировать ссылку в B, я использую метод 1. Однако метод 1 укажет мне предупреждение, которое понятно.

Следовательно, я должен отказаться от использования метода 2, используя динамическое распределение памяти.

Есть ли какой-либо лучший способ, который я могу использовать, без необходимости ручного распределения памяти /dellocation (ОК. Я знаю умный указатель)?

Я предпочитаю метод 1, просто мне не нравится это предупреждение.

4b9b3361

Ответ 1

Обратите внимание, что это предупреждение (поэтому оно опасно не незаконно).

Что беспокоит компилятор, так это то, что вы передаете указатель на объект, который не был полностью инициализирован. Таким образом, если указатель используется в конструкторе класса B, вы находитесь в undefined.

Итак, если вы используете это, единственное, что вы можете сделать, это назначить указатель на переменную-член (ссылку или указатель). Обратите внимание, что будьте осторожны с назначением переменной, поскольку вы можете вызвать неявное преобразование (я не уверен, что это действительно проблема, но RTTI недоступен до тех пор, пока объект не будет полностью сформирован).

Чего вы пытаетесь достичь, сохранив ссылку?

Ответ 2

Выполнение этого действия.

Однако вы должны обеспечить (я имею в виду, что компилятор не может этого сделать), что this не используется для вызова виртуальных функций, пока объект не будет полностью построен.

Ответ 3

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

struct bar_base; // interface foo wants

struct foo
{
    foo(bar_base& pX) :
    mX(pX)
    {}

    bar_base& mX;
};

struct bar_base
{
    /* whatever else */ 
protected:
    bar_base& get_base(void)
    {
        // getting `this` went here; safe because bar_base is initialized
        return *this; 
    }
};

struct bar : bar_base
{
    bar(void) :
    // bar_base is already initialized, so:
    mX(get_base())
    {}

    foo mX;
};

Очевидно, это зависит от того, что вы делаете. Это гарантирует, что вы никогда не получите поведение undefined.

Но на самом деле это просто предупреждение. Если вы обещаете никогда не использовать this в конструкторе B, вы в порядке и можете отключить предупреждение таким образом:

struct bar;

struct foo
{
    foo(bar& pX) :
    mX(pX)
    {}

    bar& mX;
};

struct bar
{
    bar(void) :
    mX(self())
    {}

    foo mX;

private:
    bar& self(void)
    {
        // fools the warning
        return *this;
    }
};

Убедитесь, что вы знаете, что вы делаете. (Возможно, он может быть перепроектирован?)

Ответ 4

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

Ответ 5

Отнесите это предупреждение всерьез. Ваш объект this еще не полностью сконструирован, и его перемещение небезопасно (если вы случайно вызываете функцию на this, вы вызываете UB). Кроме того, существуют другие методы управления памятью. Попробуйте найти конструкцию STL распределителей.

Вы также можете использовать RAII/умные указатели для достижения такого же эффекта.

Или вы пытаетесь написать сортировщик мусора/профайлер памяти?