2013-04-12 7 views
6

Я экспериментировал с новыми добавленными ссылками rvalue (в vs2012 express).Неправильная пересылка ссылки rvalue

Я ничего не понимаю. Учитывая код ниже (большая часть его взята из стандарта C++, где объясняется std :: forward).

struct A 
{ 
    A(int& i, const float& j): 
     m_i(i), 
     m_j(j){} 

    int& m_i; 
    const float& m_j; 
}; 

template<class T, class A1, class A2> 
T* factory(A1&& a1, A2&& a2) 
{ 
    return new T(a1, a2); 
} 

void test() 
{ 

    A* a1 = factory<A>(1, 1.2f); 

    //How does this work ?   
    a1->m_i = 2; 
} 

Я не понимаю, к чему привязана m_i.

Я в основном имеют ссылки Lvalue к ссылке на RValue (& & &), что реф рушится правил становится (&) только простой Lvalue реф. Но ссылка на что?

ответ

10

Я не понимаю, где m_i переплетены с.

m_i связан с аргументом конструктора A. Что такое аргумент конструктора A?

В этом случае, так как factory делает не вперед свой аргументом A (т.е. он не использует std::forward<>()), то, что в настоящее время передаются A является именующего. Это связано с тем, что a1 является с именем и названными объектами являются lvalues ​​.

типа из a1 не имеет значения, чтобы определить, является ли это a1-значение или Rvalue. Так что хотя a1 имеет тип rvalue-reference toint (int&&), как и в вашей программе, параметр a1 сам по себе является именованным объектом, и поэтому он является lvalue.

Это означает, что, поскольку m_i имеет тип-значение-ссылку на int, что m_iможет быть связаны (и действительно связан) с factory «с (именующим) параметром a1, которые будут уничтожены, когда factory() возвращаются. Другими словами, вы остаетесь с обвисшей ссылкой.

Попытка разыменовать его (как в дальнейшем в вашей программе) вызывает Неопределенное поведение.

Однако, если ваша factory() функция была пересылаются свои аргументы A «s конструктор:

template<class T, class A1, class A2> 
T* factory(A1&& a1, A2&& a2) 
{ 
    return new T(std::forward<A1>(a1), std::forward<A2>(a2)); 
} 

Это вызвало бы ошибку компилятора, поскольку механизм std::forward<>() бы убедиться, что lvalues ​​остаться lvalues, и rvalues ​​остаются rvalues. Попытка связать ссылку lvalue с rvalue является незаконной, и поэтому вызов конструктора A потерпел бы неудачу.

+0

Как отметил Скотт Мейерс, любое использование универсальной ссылки ('T &&' с типом-выведенным 'T') без либо' std :: forward', либо 'std :: move' является, по меньшей мере, сомнительным , Теперь я ясно понимаю, почему. –

3

Но ссылка на что?

Это неопределенное поведение. Как вы уже догадались, это ссылка на временное, которое было разрушено в стеке функции factory. Для того, чтобы поймать такие проблемы во время компиляции, вам нужно использовать std::forward

template<class T, class A1, class A2> 
T* factory(A1&& a1, A2&& a2) 
{ 
    return new T(std::forward<A1>(a1), std::forward<A2>(a2)); 
} 
+0

'A1 && a1' не обязательно должен быть rvalue_ref, он также может принимать значение lvalue_ref, поскольку они вводятся шаблоном. поэтому всякий раз, когда тип выводится по шаблону, и вы не должны сохранять тип ссылки во всех вызовах функций, вам нужно использовать 'std :: forward' – balki

+0

ups .... я случайно удалил свой коммант. Благодарю. Старый комментарий: мне всегда нужно использовать std :: forward с ссылками lvalue?) – Alex

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