// Example program #include <iostream> #include <string> void f(const int& x) { std::cout << "lvalue reference to const overload f(" << x << ")\n"; } void f(int&& x) { std::cout << "rvalue reference overload f(" << x << ")\n"; } #include <typeinfo> #include <string> int main() { f(3); int&& z = 3; f(z); } 

Why in this case, when f (z) is called, the const lvalue function is called, not the second, because the type z is an rvalue refference?

and the second question:

 class A { public: A() { std::cout << "A constructor" << std::endl; } ~A() { std::cout << "A destructor" << std::endl; } A(const A& other) { std::cout << "A copy constructor" << std::endl; } A(A&& other) { std::cout << "A move constructor" << std::endl; } }; class B : public A { public: B() : A() { std::cout << "B constructor" << std::endl; } ~B() { std::cout << "B destructor" << std::endl; } B(const B& other) : A(other) { std::cout << "B copy constructor" << std::endl; } B(B&& other) : A(other) { std::cout << "B move constructor" << std::endl; } }; int main() { std::vector<B> v; std::cout << ">>> Pushing first element" << std::endl; v.push_back(B()); std::cout << ">>> First element was pushed" << std::endl; } 

Why in this case A copy constructor is called, but not A move constructor: how is it connected with lvalue and rvalue, and with overloading?

update:

changed the line as stated in the excellent answer:

 B(B&& other) : A(std::move<B&>(other)) { 

Thanks to what the conclusion now looks like this:

 >>> Pushing first element A constructor B constructor A move constructor B move constructor B destructor A destructor >>> First element was pushed >>> Pushing second element A constructor B constructor A move constructor B move constructor A copy constructor B copy constructor B destructor A destructor B destructor A destructor >>> Second element was pushed B destructor A destructor B destructor A destructor 

Updated question:

The last two copy ctor'a are called as far as I understand it when the magnitude of the vector increases and when they are copied (as I understand it, the implementation is through a dynamic array), if not the reason, correct it. How to make so that those places was called move ctor?

tried this:

 v.push_back(std::move<B&&>)B()(); 

Changed nothing.
When these elements are already in the vector, as far as I understand, they are already lvalue.

The strangeness is that the task (the study of the behavior of rvalue and lvalue) says that you can additionally change somehow the same line that was mentioned above by some special specifier, which for the sake of such cases is added to c ++ 11, to call the move constructor in this case. Tell me how to do this?

  • If you have a new question, then ask it a new question. - VladD

2 answers 2

Named rvalue-ссылки treated as lvalue .

In this ad

 int&& z = 3; 

The variable z is of type rvalue-ссылки , which is bound to a temporary expression consisting of an integer literal equal to 3. However, the variable z is an lvalue .

For example, you can use the get address operator

 std::cout << ( void * )&z << std::endl; 

This, for example, is explicitly stated in Section 7 of Section 5, Expressions of the C ++ Standard

In general, this is the case of a reference. references or nos.

Therefore, when the function f is called, the compiler looks for an overloaded function that takes an lvalue as an argument. As a result, the function declared as

 void f(const int& x) { std::cout << "lvalue reference to const overload f(" << x << ")\n"; } 

You can turn z into rvalue using a static_cast type static_cast , or the standard function std::move , or just for an arithmetic type, for example, by putting a unary plus sign.

Below is a demo program that shows the approaches described for turning an lvalue into an rvalue , and that the variable z , although it has the type of an rvalue-ссылки , is nevertheless an lvalue .

 #include <iostream> #include <functional> void f(int&& x) { std::cout << "rvalue reference overload f(" << x << ")\n"; } void f(const int& x) { std::cout << "lvalue reference to const overload f(" << x << ")\n"; } int main() { f( 3 ); int &&z = 3; f( z ); f( static_cast<int &&>( z ) ); f( std::move( z ) ); f( +z ); return 0; } 

Output of the program to the console

 rvalue reference overload f(3) lvalue reference to const overload f(3) rvalue reference overload f(3) rvalue reference overload f(3) rvalue reference overload f(3) 

A similar situation occurs with the constructor parameter. Although it is of type rvalue-ссылки , the parameter itself is nevertheless an lvalue . Therefore, when it is passed to the base class as an argument, the constructor of the base class will be called, which takes an lvalue .

If you want to learn more about this material, I advise you to read the article by Scott Myers in the ACCU Overload magazine №111 for October 2012 Universal References in C ++ 11 .

This is an international magazine of professional programmers.

By the way, at the same time in the same magazine ACCU Overload # 126 for April 2015 you can read my article iterator_pair - a simple and useful iterator adapter. :)

Regarding ACCU , it is

The ACCU is an organization of programmers. It is a good way. We are dedicated to raising the standard of programming. ACCU members have been contributed by the ACCU members.

As for your additional question, just reserve enough space in the vector, such as

 v.reserve( 2 ); 

Then there will be no redistribution of memory, and, accordingly, copying of vector objects to a new memory area.

Or, specify a noexcept specifier from the move constructor. Then, instead of the copy constructor, the displacement constructor will be called.

Here is a simple example.

 #include <iostream> #include <vector> struct B { B() { std::cout << "B()" << std::endl; } B( const B & ) { std::cout << "B( const B & )" << std::endl; } B( B && ) noexcept { std::cout << "B( B && )" << std::endl; } // ^^^^^^^ ~B() { std::cout << "~B()" << std::endl; } }; int main() { std::vector<B> v; std::cout << "adding first element" << std::endl; v.push_back( B() ); std::cout << "\nadding second element" << std::endl; v.emplace_back( B() ); return 0; } 
  • About your last example - you probably meant noexcept ? - Harry
  • @Harry Yes, I meant noexcept. :) - Vlad from Moscow

By virtue of my understanding - in the standards I am not so strong as to be offhand quoted.

In the first part, declare z as you like, but if there is a name, there is an address, which means it will be simply an int .

In the second, after the rvalue link is passed as a parameter, it receives a name, which means it is now an lvalue. If you want a moving constructor, do this:

 B(B&& other) : A(std::move(other)) { 

The same method can be applied to f(z) : f(std::move(z)) .

Specific references to the standard, I think, will give @Vlad from Moscow .

  • Yes, it was the right answer, the problem remained with the lower two calls, as far as I understand it with an increase in the vector. Would you answer ? Described in detail in the updated question above. - Avenger
  • one
    As I expected, @VladfromMoscow thoroughly answered you with only one amendment, the magic specifier is not nothrow , but noexcept . By the way, I should note that the standard is a standard, but, for example, the same Visual C ++ just ignores the qualifiers and always calls only the relocating constructor :( - Harry