1

I was studying move constructors when I came across this sample of code on official Microsoft C++ documentation which was trying to explain basic move constructor.

Link to article:- https://learn.microsoft.com/en-us/cpp/cpp/constructors-cpp?view=msvc-170#move_constructors

Context :-

The compiler chooses a move constructor in certain situations where the object is being initialized by another object of the same type that is about to be destroyed and no longer needs its resources. The following example shows one case when a move constructor is selected by overload resolution. In the constructor that calls get_Box(), the returned value is an xvalue (eXpiring value). It is not assigned to any variable and is therefore about to go out of scope. To provide motivation for this example, let's give Box a large vector of strings that represent its contents. Rather than copying the vector and its strings, the move constructor "steals" it from the expiring value "box" so that the vector now belongs to the new object. The call to std::move is all that's needed because both vector and string classes implement their own move constructors.

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;

class Box {
public:
    Box() { std::cout << "default" << std::endl; }
    Box(int width, int height, int length)
       : m_width(width), m_height(height), m_length(length)
    {
        std::cout << "int,int,int" << std::endl;
    }
    Box(Box& other)
       : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        std::cout << "copy" << std::endl;
    }
    Box(Box&& other) : m_width(other.m_width), m_height(other.m_height), m_length(other.m_length)
    {
        m_contents = std::move(other.m_contents);
        std::cout << "move" << std::endl;  // HERE
    }
    int Volume() { return m_width * m_height * m_length; }
    void Add_Item(string item) { m_contents.push_back(item); }
    void Print_Contents()
    {
        for (const auto& item : m_contents)
        {
            cout << item << " ";
        }
    }
private:
    int m_width{ 0 };
    int m_height{ 0 };
    int m_length{ 0 };
    vector<string> m_contents;
};

Box get_Box()
{
    Box b(5, 10, 18); // "int,int,int"
    b.Add_Item("Toupee");
    b.Add_Item("Megaphone");
    b.Add_Item("Suit");

    return b;
}

int main()
{
    Box b; // "default"
    Box b1(b); // "copy"
    Box b2(get_Box()); // "move"  //HERE
    cout << "b2 contents: ";
    b2.Print_Contents(); // Prove that we have all the values

    char ch;
    cin >> ch; // keep window open
    return 0;
}

In the main() function when calling Box b2(get_Box()); // "move" , wasn't the compiler meant to call the move constructor defined in the class definition Box(Box&& other) ? BUT when I run the code on my machine I receive the following output :

default
copy
int,int,int
b2 contents: Toupee Megaphone Suit

Why is "move" not being printed? std::cout << "move" << std::endl;

Is the move constructor defined in the class not being called? If not then what's happening ? Which constructor is doing the job?

Also when I execute Box b2(std::move(get_Box())); // "move" instead of Box b2(get_Box()); // "move" , I get the following output

default
copy
int,int,int
move
b2 contents: Toupee Megaphone Suit

One can clearly see that this time "move" std::cout << "move" << std::endl; gets printed. If someone could explain in detail what's going on?

  • Related: https://stackoverflow.com/q/12953127 – Ch3steR Jan 02 '22 at 08:33
  • 3
    That's copy elision: [What are copy elision and return value optimization?](https://stackoverflow.com/questions/12953127/what-are-copy-elision-and-return-value-optimization) – Enlico Jan 02 '22 at 08:34

0 Answers0