Классы, Rvalues ​​и Rvalue Список -- c++ поле с участием reference поле с участием rvalue-reference поле с участием rvalue поле с участием lvalue пол Связанный проблема

Classes, Rvalues and Rvalue References


14
vote

проблема

русский

Lvalue - это значение, связанное с окончательной областью памяти, тогда как rvalue - это значение выражения, существование которого является временным, а не обязательно относится к окончательному региону памяти. Всякий раз, когда Lvalue используется в положении, в котором ожидается, что rvalue, компилятор выполняет преобразование Lvalue-rvalue, а затем протекает с оценкой.

http://www.eetimes.com/discussion/programming-pointers/4023341 / Lvalues-and-rvalues ​​

Всякий раз, когда мы строим временный (анонимный) объект класса или верните объект временного класса из функции, хотя объект временно, он адресуется. Однако объект все еще является действительным рвалем. Это означает, что объект A) адресуемая RValue или B) неявно преобразуется из Lvalue на RValue, когда компилятор ожидает, что используют Lvalue.

Например:

 <код> class A { public:     int x;     A(int a) { x = a; std::cout << "int conversion ctor "; }     A(A&) { std::cout << "lvalue copy ctor "; }     A(A&&) { std::cout << "rvalue copy ctor "; } }; A ret_a(A a)  {     return a; }  int main(void) {     &A(5); // A(5) is an addressable object     A&& rvalue = A(5); // A(5) is also an rvalue }   

Мы также знаем, что временные объекты возвращены (в следующем случае a ) по функциям относятся lvalues, поскольку этот сегмент кода:

 <код> int main(void) {     ret_a(A(5)); }   

дает следующий выход:

<Код> int conversion ctor

<Код> lvalue copy ctor

Указывает, что вызов функции <код> ret_a с использованием фактического аргумента <код> A(5) вызывает конструктор преобразования <код> A::A(int) , который создает формальный аргумент функции <код> 1 Socks 2 Shoes 3 Internal 4 Pants 0 со значением 5.

Когда функция завершает выполнение, то она создает временный <код> 1 Socks 2 Shoes 3 Internal 4 Pants 1 объекта, используя <код> 1 Socks 2 Shoes 3 Internal 4 Pants 2 как его аргумент, который вызывает <код> 1 Socks 2 Shoes 3 Internal 4 Pants 3 . Однако, если бы мы были удалить <код> 1 Socks 2 Shoes 3 Internal 4 Pants 4 из списка перегруженных конструкторов, возвращенный временный объект все равно будет соответствовать конструктору RValue-Reference <код> 1 Socks 2 Shoes 3 Internal 4 Pants 5 .

Это то, что я не совсем понимаю: как объект <код> 1 Socks 2 Shoes 3 Internal 4 Pants 6 соответствует как ссылку на RValue, так и ссылку на Lvalue? Понятно, что <код> 1 Socks 2 Shoes 3 Internal 4 Pants 7 - лучший матч, чем <код> 1 Socks 2 Shoes 3 Internal 4 Pants 8 (и, следовательно, <код> 1 Socks 2 Shoes 3 Internal 4 Pants 9 должен быть Lvalue). Но, поскольку ссылка RVAlue не может быть инициализирована с Lvalue, учитывая, что формальный аргумент <код> class A { public: int x; A(int a) { x = a; std::cout << "int conversion ctor "; } A(A&) { std::cout << "lvalue copy ctor "; } A(A&&) { std::cout << "rvalue copy ctor "; } }; A ret_a(A a) { return a; } int main(void) { &A(5); // A(5) is an addressable object A&& rvalue = A(5); // A(5) is also an rvalue } 0 - это Lvalue, он не должен иметь возможность сопоставить вызов <код> class A { public: int x; A(int a) { x = a; std::cout << "int conversion ctor "; } A(A&) { std::cout << "lvalue copy ctor "; } A(A&&) { std::cout << "rvalue copy ctor "; } }; A ret_a(A a) { return a; } int main(void) { &A(5); // A(5) is an addressable object A&& rvalue = A(5); // A(5) is also an rvalue } 1 . Если компилятор делает преобразование Lvalue-rvalue, это было бы тривиально. Тот факт, что преобразование от «A» на «A & AMP»; Также тривиально обе функции должны иметь одинаковую неявную последовательность преобразования рангов и, следовательно, компилятор не должен иметь возможность выводить функцию лучшего соответствия, когда <код> lvalue copy ctor22 и <код> class A { public: int x; A(int a) { x = a; std::cout << "int conversion ctor "; } A(A&) { std::cout << "lvalue copy ctor "; } A(A&&) { std::cout << "rvalue copy ctor "; } }; A ret_a(A a) { return a; } int main(void) { &A(5); // A(5) is an addressable object A&& rvalue = A(5); // A(5) is also an rvalue } 3 Перегруженная функция набор кандидата.

Более того, вопрос (который я спросил):

Как данный объект соответствует как ссылку на Rvalue, так и ссылки на Lvalue?

Английский оригинал

An lvalue is a value bound to a definitive region of memory whereas an rvalue is an expression value whose existence is temporary and who does not necessarily refer to a definitive region of memory. Whenever an lvalue is used in a position in which an rvalue is expected, the compiler performs an lvalue-to-rvalue conversion and then proceeds with evaluation.

http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues

Whenever we construct a temporary (anonymous) class object or return a temporary class object from a function, although the object is temporary, it is addressable. However, the object still is a valid rvalue. This means that the object is a) an addressable rvalue or b) is being implicitly converted from an lvalue to an rvalue when the compiler expects an lvalue to be used.

For instance:

class A { public:     int x;     A(int a) { x = a; std::cout << "int conversion ctor "; }     A(A&) { std::cout << "lvalue copy ctor "; }     A(A&&) { std::cout << "rvalue copy ctor "; } }; A ret_a(A a)  {     return a; }  int main(void) {     &A(5); // A(5) is an addressable object     A&& rvalue = A(5); // A(5) is also an rvalue } 

We also know that temporary objects returned (in the following case a) by functions are lvalues as this code segment:

int main(void) {     ret_a(A(5)); } 

yields the following output:

int conversion ctor

lvalue copy ctor

Indicating that the call to the function ret_a using actual argument A(5) calls the conversion constructor A::A(int) which constructs the function's formal argument a with the value 5.

When the function completes execution, it then constructs a temporary A object using a as its argument, which invokes A::A(A&). However, if we were to remove A::A(A&) from the list of overloaded constructors, the returned temporary object would still match the rvalue-reference constructor A::A(A&&).

This is what I'm not quite understanding: how can the object a match both an rvalue reference and an lvalue reference? It is clear that A::A(A&) is a better match than A::A(A&&) (and therefore a must be an lvalue). But, because an rvalue reference cannot be initialized to an lvalue, given that the formal argument a is an lvalue, it should not be able to match the call to A::A(A&&). If the compiler is making an lvalue-to-rvalue conversion it would be trivial. The fact that a conversion from 'A' to 'A&' is also trivial, both functions should have identical implicit conversion sequence ranks and therefore, the compiler should not be able to deduce the best-matching function when both A::A(A&) and A::A(A&&) are in the overloaded function candidate set.

Moreover, the question (which I previously asked) is:

How can a given object match both an rvalue reference and an lvalue reference?

</div
              
   
   

Список ответов

6
 
vote
vote
Лучший ответ
 

Для меня:

 <код> int main(void) {     ret_a(A(5)); }   

Выход:

 <код> int conversion ctor rvalue copy ctor   

(то есть rvalue, не lvalue). Это ошибка в вашем компилятере. Однако это понятно, как правила для этого поведения изменилось всего несколько месяцев назад (ноябрь 2010 г.). Больше на этом ниже.

Когда функция завершает выполнение, Затем он сконструирует временный <код> A Объект, использующий <код> a как его аргумент, который вызывает <код> A::A(A&) .

на самом деле нет. Когда функция <код> ret_a завершает выполнение, он затем создает временный <код> A объекта, используя <код> a как его аргумент, который вызывает <код> A:A(A&&) Это связано с [class.copy] / p33] 1 :

Когда критерии для вызовы операция копирования выполняется или будет выполнена Сохранить для того, что источник Объект является функциональным параметром, а также Объект, который будет скопирован, обозначен Lvalue, разрешение перегрузки Выберите конструктор для копии впервые исполняется, как будто объект был обозначается рвалею. Если перегрузка Разрешение не удается или если тип Первый параметр выбранного Конструктор не является ссылкой на рвале к типу объекта (возможно, CV-квалифицированный), разрешение перегрузки снова выполнил, учитывая объект как Lvalue. [Примечание: это Двухступенчатое разрешение перегрузки должно быть выполняется независимо от того, копия Элиз будет происходит. Определяет то конструктор, который будет называться, если элакт не выполнено, а выбранные Конструктор должен быть доступен, даже если Вызов модифицируется. - Конец примечания]

Однако, если вы удалите <код> A::A(A&&) конструктора, затем <код> int conversion ctor rvalue copy ctor 0 будет выбран для возврата. Хотя в этом случае, то построение аргумента <код> int conversion ctor rvalue copy ctor 1 не удается, поскольку вы не можете построить его, используя rvalue. Однако игнорирование того, что на данный момент я считаю, что ваш конечный вопрос:

Как данный объект соответствует как Ссылка RValue и Lvalue Ссылка?

Ссылаясь на утверждение:

 <код> int conversion ctor rvalue copy ctor 2  

И ответ находится в приведенном выше абзаце из проекта стандарта: первое разрешение перегрузки пробуется как если бы <Код> int conversion ctor rvalue copy ctor 3 - это rvalue. И если это не удается, разрешение перегрузки снова опробовано, используя <код> int conversion ctor rvalue copy ctor 4 как lvalue. Этот двухэтапный процесс пробурен только в контексте, в котором выделение копирования допустимо (например, оператор возврата).

Черновик C ++ 0x совсем недавно был изменен, чтобы позволить двухступенчатую процесс разрешения перегрузки при возврате аргументов, которые были переданы по значению (как в вашем примере). И это причина для различного поведения от различных компиляторов, которые мы видим.

 

For me:

int main(void) {     ret_a(A(5)); } 

Yields:

int conversion ctor rvalue copy ctor 

(i.e. rvalue, not lvalue). This is a bug in your compiler. However it is understandable as the rules for this behavior changed only a few months ago (Nov. 2010). More on this below.

When the function completes execution, it then constructs a temporary A object using a as its argument, which invokes A::A(A&).

Actually no. When the function ret_a completes execution, it then constructs a temporary A object using a as its argument, which invokes A:A(A&&). This is due to [class.copy]/p33]1:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. — end note ]

However if you remove the A::A(A&&) constructor, then A::A(&) will be chosen for the return. Although in this case, then the construction of the argument a will fail because you can't construct it using an rvalue. However ignoring that for the moment, I believe your ultimate question is:

How can a given object match both an rvalue reference and an lvalue reference?

in referring to the statement:

return a; 

And the answer is in the above quoted paragraph from the draft standard: First overload resolution is tried as if a is an rvalue. And if that fails, overload resolution is tried again using a as an lvalue. This two-stage process is tried only in the context wherein copy elision is permissible (such as a return statement).

The C++0x draft has just recently been changed to allow the two-stage overload resolution process when returning arguments that have been passed by value (as in your example). And that is the reason for the varying behavior from different compilers that we are seeing.

</div
 
 
         
         

Связанный проблема

57  Как сделать макрос C ++ вести себя как функция?  ( How do i make a c macro behave like a function ) 
Допустим, по какой-то причине вам нужно написать макрос: <код> MACRO(X,Y) . (давайте предположим, что есть веская причина, по которой вы не можете использова...

501  Как использовать постоянную PI в C ++  ( How to use the pi constant in c ) 
Я хочу использовать постоянные и тригонометрические функции PI в некоторой программе C ++. Я получаю тригонометрические функции с помощью <код> include <math....

2  Создание хеша для данных больше, чем память (без зарядки)  ( Generating a hash for data larger than memory without getting arrested ) 
Добрый послеобеденный переполнец! ;) Что я хочу сделать: Я заинтересован в проверке передаваемой целостности файлов. Как я подошел к нему: Я рассм...

0  Правильный способ использования вариационного шаблона функции вызова со строковыми аргументами C ++  ( Proper way of using variadic template function call with string arguments c ) 
Здравствуйте, что не то, что я здесь делаю, используя вариадические шаблоны через строку? Как правильно использовать его для достижения заданий ниже? <код> ...

1  Шаблон статических классов через динамические связанные библиотеки  ( Template static classes across dynamic linked libraries ) 
У меня есть классовый класс со статическим значением, как это: <код> template <class TYPE> class A{ static TYPE value; }; в коде dll I назначаю ст...

0  Как захватывать события, выпущенные из нового окна всплывающего  ( How to capture events fired from new popup ie window ) 
Приветствия! <Сильная> Ситуация: My ActiveX DLL содержит индивидуальный webbrowser. WebBrowser отображает веб-страницу. Когда пользователь нажимает на сс...

-1  C ++ DO В то время как проблемы с петлей [закрыто]  ( C do while loop issues ) 
<в сторону CLASS = "S-NEWACTS S-WELTIVE__info JS-Post-New Imide MB16« Роль = «Статус»> <Путь d = "M15 6.38A6.48 6.48 0 007.78. 04H-.02A6.49 6.49 0 002.05 ...

-1  Бросить исключение, когда неправильный тип введен в  ( Throw exception when a wrong type is keyed in ) 
Я должен написать программу C ++, в которой функция состоит в том, чтобы прочитать два номера double Тип чисел из клавиатуры и добавить <код> try BLOCK, чт...

-1  Приложение C ++ в массивах с использованием арифметического указателя  ( C app on arrays using pointer arithmetic ) 
Вопрос: как я могу генерировать случайное животное из массива, используя эту функцию? <код> const int MAX =12; //12 animals const int MAXSTR = 10; ...

6  Singleton & Multi-Threading  ( Singleton multi threading ) 
У меня есть следующий класс <код> class Singleton { private: static Singleton *p_inst; Singleton(); public: static Singleton * instance()...

0  Как настроить VS2008 для эффективного развития C ++  ( How to setup vs2008 for efficient c development ) 
Обычно I Программируйте в C #, но были вынуждены выполнять работу в C ++. Похоже, что интеграция с Visual Studio (2008) действительно плохо по сравнению с C #...

-1  Неожиданный идентификатор ошибки - не уверен, почему (C ++)  ( Unexpected error id not sure why c ) 
IM Реализация программы C ++, по соображениям проекта оно должно быть включено в один файл, поэтому я не могу поставить то, что вы обычно в отдельном файле за...

5  Что такое "для (x: y)"?  ( What is for x y ) 
Итак, я оглянулся на межпубки о нитках, и я пришел в блог / учебную вещь о нитках, но то, что меня смущено, была эта линия, которую он использовал <код> for...

-4  Петля, которая компилирует и работает в INT основной функции не скомпилируется при введении в отдельную функцию [закрыто]  ( Loop that compiles and runs in int main function wont compile when put into a se ) 
<в сторону CLASS = "S-NEWACTS S-WELTIVE__info JS-Post-New Imide MB16« Роль = «Статус»> закрыто. Этот вопрос нуждается в Детали отладки . В настоящее вр...

3  Как создавать закрытые зоны (выпуклые многоугольники) от набора сегментов линии?  ( How to create closed areas convex polygons from set of line segments ) 
Следующая проблема находится в 2D, поэтому некоторые упрощения могут быть сделаны при предложении ответов. Мне нужно создать закрытые области (определены ли...

Связанный проблема

57  Как сделать макрос C ++ вести себя как функция? 
501  Как использовать постоянную PI в C ++ 
2  Создание хеша для данных больше, чем память (без зарядки) 
0  Правильный способ использования вариационного шаблона функции вызова со строковыми аргументами C ++ 
1  Шаблон статических классов через динамические связанные библиотеки 
0  Как захватывать события, выпущенные из нового окна всплывающего 
-1  C ++ DO В то время как проблемы с петлей [закрыто] 
-1  Бросить исключение, когда неправильный тип введен в 
-1  Приложение C ++ в массивах с использованием арифметического указателя 
6  Singleton & Multi-Threading 
0  Как настроить VS2008 для эффективного развития C ++ 
-1  Неожиданный идентификатор ошибки - не уверен, почему (C ++) 
5  Что такое "для (x: y)"? 
-4  Петля, которая компилирует и работает в INT основной функции не скомпилируется при введении в отдельную функцию [закрыто] 
3  Как создавать закрытые зоны (выпуклые многоугольники) от набора сегментов линии?