Список использования со ссылками, изменяет поведение при использовании в качестве члена - PullRequest
0 голосов
/ 11 июня 2018

Экспериментируя с этим вопросом / ответом https://stackoverflow.com/a/50649120/225186 Я создал то, что кажется легальным рекурсивным самореференциальным классом, который реализует циклический список:

struct node{
    int val;
    node const& next;
};

int main(){
    node s{3, {4, s}};

    assert(s.val == 3);
    assert(s.next.val == 4);
    assert(&s.next.next == &s);
    assert(s.next.next.val == 3);
}

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

struct A{
    node n;
    int i;
    A(int a, int b) : n{a, {b, n}}{} // warning here, also tried n{a, node{b, n}}
};

int main(){
    A a(3, 4);
    assert( a.n.val == 3 );
    assert(&(a.n.next.next) == &(a.n)); // this assert fail and 
    assert( a.n.next.val == 4 ); // segmentation fault here
}

Получаемое предупреждение - gcc: warning: a temporary bound to ‘A::n’ only persists until the constructor exits [-Wextra].Я не верю, что предупреждение является правильным, однако оно согласуется с более поздней ошибкой времени выполнения.

Я допускаю, что класс не является общепринятым, однако, как это может быть, что класс, которыйэто меняет поведение внутри класса?

Я что-то упустил?

1 Ответ

0 голосов
/ 11 июня 2018

Агрегированная инициализация позволяет привязывать ссылки к временным файлам (, что приводит к увеличению продолжительности жизни ).Ваш первый пример - агрегатная инициализация , потому что node - агрегат.

Однако в списке инициализатора члена конструктора неправильно сформирована ссылка на временную ссылку (C +)+17 class.base.init / 11).Это связано с тем, что в этой ситуации нет продления срока службы, и его разрешение неизбежно приведет к зависанию.Во втором примере node не является агрегатом, поскольку в нем есть предоставленный пользователем конструктор.

...