2014-01-02 2 views
4
#include <iostream> 
struct Bar 
{ 
    int nb_; 
    Bar(int nb) :nb_(nb){} 
    ~Bar() 
    { 
     std::cout << "~Bar" << "\n"; 
    } 
}; 

struct Foo 
{  
    template<class T> 
    Foo(T&& param) :bar_(std::move(param)) 
    { 
     std::cout << "Foo" << "\n"; 
    } 
    ~Foo() 
    { 
     std::cout << "~Foo" << "\n"; 
    } 

    Bar&& bar_; 
}; 

int main() 
{  
    { 
     Foo foo(Bar(1)); 
    } 

    std::cin.ignore(); 
} 

//Output: 
Foo 
~Bar 
~Foo 

Является ли эта программа законной C++? Будет ли bar_ становиться обвисшей ссылкой после того, как конструктор Foo будет закончен?rvalue reference как поле объекта

Если это не является законным с точки зрения стандарта C++, когда полезно иметь ссылку rvalue в качестве поля?

ответ

6

Может ли bar_ стать обвисшей ссылкой после того, как конструктор Foo будет закончен?

Не совсем. Это становится болтающейся ссылкой в ​​том месте, где разрушено временное, созданное Bar(1): в конце полного выражения Foo foo(Bar(1)).

Это также показывает пример использования опорных элементов RValue, например forward_as_tuple:

struct woof 
{ 
    using my_tuple = std::tuple<std::vector<int>, std::string>; 
    my_tuple m; 

    woof(my_tuple x) : m(std::move(x)) {} 
}; 

std::vector<int> v{1,2,3,4,5}; 
woof w(forward_as_tuple(std::move(v), std::string{"hello world"})); 

forward_as_tuple может хранить RValue ссылки (здесь: в tuple<vector<int>&&, string&&>), который по-прежнему могут быть использованы CTOR из woof к переместить v и временно созданный std::string{"hello world"}.

2

Да, bar_ станет связующим звеном после завершения конструктора.

Редко имеет смысл хранить ссылку, но в некоторых случаях существует. Я не думаю, что существует различие между различными типами ссылок. Хранимая ссылка ссылается на другой объект, и вам нужно убедиться, что объект остается действительным при использовании ссылки.

Обратите внимание, что если вы пишете

Bar b(1); 
Foo foo(std::move(b)); 

foo не переместили b, он просто хранить ссылку на него. b все еще действителен и может быть использован. Только если у вас есть член Foo, который фактически перемещается из сохраненной ссылки, будет перемещен b.

+0

* «Да,« bar_ »станет болтающей ссылкой после завершения конструктора». * Я знал, что прочитал это раньше в Стандарте, теперь я думаю, что нашел контекст: это утверждение относится к созданным временным в инициализаторе ctor (mem-initializer-list), но не временные, переданные * на * ctor в качестве аргументов, [class.temporary]/5. – dyp

+0

@DyP Просто пояснить: это утверждение относится к конкретному примеру, который дал OP, где я предположил, что «после завершения конструктора он должен сказать» после выражения «Foo foo (Bar (1));». Вы, конечно, правильно указали, что это не совсем то же самое, и вы уже получили мой +1 на свой ответ :) –

+0

Это просто звучало так знакомо, что я был смущен на мгновение, о чем он говорит;) – dyp

Смежные вопросы