0

I am trying to grasp the concept of move semantics, rvalues, lvalues in c++ and am facing a problem. I am first looking at this popular answer - https://stackoverflow.com/a/3109981/9576161

I wrote a small program based on that reply to understand what is going on. I am using g++ (on linux) and the -fno-elide-constructors for compiling without rvalue optimization by the compiler.

Here is the small program:

#include <iostream>                                                                                                                                                      
#include <cstring>                                                                                                                                                       

using namespace std;                                                                                                                                                     

class string  {                                                                                                                                                          

    public:                                                                                                                                                              
        char* data;                                                                                                                                                      
        string (const char* p) {                                                                                                                                         
            cout << "Constructor 1 called\n";                                                                                                                            
            size_t size = strlen(p) + 1;                                                                                                                                 
            data = new char[size];                                                                                                                                       
            cout << "this location is: " << this << endl;
            memcpy (data,p,size);
        }

        string (string&& that) {
            cout << "Constructor 2 called\n";
            //cout << "data is " << data << " data location is: " << &data << endl;
            cout << "data location is: " << &data << endl;
            cout << "that.data is " << that.data << " that.data location is: " << &that.data << endl;
            data = that.data;
            that.data = nullptr;
            cout << "this location is: " << this << " data is: " << data << endl;
            cout << "data location is: " << &data << endl;
            cout <<  "that.data location is: " << &that.data << endl;
        }

        ~string() {
            delete[] data;
            cout << "Destructor called for object located at: " << this << endl;
        }

        void print() {
            cout << "String is: " << data << endl;
        }
};

int main () {
    ::string R = "12345";
    cout << "R constructed and located at: " << &R << endl << endl;
    return 0;
}

On running the program, I see the following result:

ubuntu@thinkpad:~/programming_practice/c_projects$ g++ -fno-elide-constructors move_semantics_short.cpp 
ubuntu@thinkpad:~/programming_practice/c_projects$ ./a.out 
Constructor 1 called
this location is: 0x7fffac01bb80
Constructor 2 called
data location is: 0x7fffac01bb78
that.data is 12345 that.data location is: 0x7fffac01bb80
this location is: 0x7fffac01bb78 data is: 12345
data location is: 0x7fffac01bb78
that.data location is: 0x7fffac01bb80
Destructor called for object located at: 0x7fffac01bb80
R constructed and located at: 0x7fffac01bb78

Destructor called for object located at: 0x7fffac01bb78
ubuntu@thinkpad:~/programming_practice/c_projects$ 

Notice the line data = that.data in the second constructor (where it says "Constructor 2 is called"). What does it do? Aren't data and that.data both character pointers? Why is data not changing in value? Shouldn't data now equal the value of that.data which is 0x7fffac01bb80? Instead it seems like some kind of memcopy is occurring and the character string that that.data points to is now pointed to by data. Any hints on what is going on would be helpful.

urmish
  • 127
  • 1
  • 6
  • `data` sure better be changing values. It just stole `that`'s `data` and nulls it to prevent accidents a line later. – user4581301 Jun 05 '18 at 00:27
  • You don't need to write an entire class to test what two pointers do when assigned to each other. – PaulMcKenzie Jun 05 '18 at 00:27
  • 2
    It is so nice to see `string` as a class name when `using namespace std;` is used as well. Great idea! – Slava Jun 05 '18 at 00:30
  • @user4581301 I don't understand. `data` is a character pointer, isn't it? Am I not printing the value of the pointer correctly? I think that is where the problem lies. Instead of `&data`, I think `(void *)data` would `cout` the actual pointer value. Is that right? – urmish Jun 05 '18 at 00:31
  • @slava I am using `::`. Sorry for the confusion. – urmish Jun 05 '18 at 00:31
  • I believe you are confusing `data` (a pointer) `&data` (a pointer-to-pointer). – jcai Jun 05 '18 at 00:34
  • I think I posted this question in a hurry. Should've thought about it a little more before posting. Please delete it if required. To print the value of the pointer I should've typecasted it with `(void *)` instead of `&` which prints the location of `data`. – urmish Jun 05 '18 at 00:35

1 Answers1

2

The type of &data is char**. That is, it's the memory location of the pointer that stores the memory location of some char.

data = that.data; does not make &data equal &that.data. It just makes data and that.data equal. They now point to the same char, but they each exist independently in memory.

If instead of printing data's address, you print the address stored in data, you can see that you are stealing the array of chars that was owned by that in your move constructor.

Miles Budnek
  • 28,216
  • 2
  • 35
  • 52