Вот пример кода со ссылочным членом для передачи аргумента конструктора по значению:

struct A
{
    A(std::string name): name_(name){}
    std::string name_;
};

struct B
{
    B(A a): a_(a)
    {
    }
    A& a_;
};

int main()
{
    std::unique_ptr<B> b;
    {
        A a("a");
        b.reset(new B(a));
    }
    b->a_.name_ = "b";

    return 0;
}

a_ по-прежнему относится к существующему объекту в этой строке b->a_.name_ = "b"? Это тот же случай, что и возврат ссылки на локальный объект функции?

2
Irbis 2 Апр 2019 в 22:18

1 ответ

Лучший ответ

Обращается ли a_ к существующему объекту в этой строке b-> a_.name_ = "b"?

Неа. Это неопределенное поведение.

В частности, конструктор B

B(A a): a_(a)
{
}

Создает висящую ссылку .

Жизнеспособность параметра a ограничена областью действия вызова конструктора. После завершения работы конструктора объект a будет уничтожен. Следовательно, инициализированная вами ссылка a_ указывает на уничтоженный объект.

Однако когда вы пытаетесь получить к нему доступ:

b->a_.name_ = "b";

Вы фактически вызываете неопределенное поведение, потому что объект больше не существует (и это плохо!).


Это тот же случай, что и возврат ссылки на локальный объект функции?

Если вы вернете ссылку на объект, который больше не существует, и попытаетесь получить к нему доступ, что ж ... все то же поведение undefined: висячая ссылка.


Дополнительное примечание

Судя по построению вашего кода, следующее изменение все еще неверно:

B(A& a): a_(a)
    {
    }

Обратите внимание, что параметр теперь передается по ссылке.

В самом деле, даже если вы не возьмете копию объекта, указанный A будет уничтожен, когда вы попытаетесь получить к нему доступ:

{ 
     A a("a");
     b.reset(new B(a));
}  // Here a will be destroyed because out of scope (as automatic variable).
2
Biagio Festa 2 Апр 2019 в 21:06