Setu
Setu

Reputation: 986

Why are all of my "this" pointers the same value?

I'm working on the following code snippet:

#include <iostream>                                                                                                                                                                                            
#include <vector>

class myclass
{
    public:
        myclass()
        {
            std::cout << this << std::endl;
        }
};

int main()
{
    std::vector<myclass> v;
    for(uint32_t i = 0; i < 10; i++)
        v.push_back(myclass());
    return 0;
}

I'm compiling the code using g++ main.cpp. When I execute the compiled binary, I get:

0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab
0x7ffebb8f8cab

My question is why are all the this pointers identical? If I'm creating 10 different objects of the same class, there should be 10 distinct this pointers. Right?

As far as I understand, my code is currently using the references of the same objects to populate the vector v. However, what I want are 10 distinct objects of myclass. How can I get this? This code is a part of a larger project and that project has some issues with new and delete. So I cannot use that API. What am I doing wrong and how can I fix this?

Upvotes: 44

Views: 3900

Answers (1)

Chris
Chris

Reputation: 36620

As noted in comments, you're seeing the this pointer for a temporary and then copying the temporary into the vector. Since the temporary is temporary your system is reusing the same memory location on each loop iteration.

However, if you print the this pointer for the vector elements, you will notice they are placed in sequential memory locations as you would expect for a vector.

Despite the myclass struct having no data members, it takes up 1 byte of memory space to satisfy the requirement for unique pointers.

#include <iostream>                                                                                                                                                                                            
#include <vector>

struct myclass {
    myclass() {
        std::cout << "Construct: " << this << std::endl;
    }

    void print() const {
        std::cout << "Print: " << this << std::endl;
    }
};

int main() {
    std::vector<myclass> v;
    for (uint32_t i = 0; i < 10; i++)
        v.push_back(myclass());

    std::cout << "\n";

    for (auto &x : v) 
        x.print();
        
    return 0;
}

Output:

Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428
Construct: 0x7fffd3d15428

Print: 0x7fffcb2b0080
Print: 0x7fffcb2b0081
Print: 0x7fffcb2b0082
Print: 0x7fffcb2b0083
Print: 0x7fffcb2b0084
Print: 0x7fffcb2b0085
Print: 0x7fffcb2b0086
Print: 0x7fffcb2b0087
Print: 0x7fffcb2b0088
Print: 0x7fffcb2b0089

If we add a copy constructor to myclass we can see the copying from temporaries to the vector.

Note: vectors may reallocate and move their contents if size exceeds capacity. To avoid this possibility in this case I've reserved a capacity of 10 for the vector v.

#include <iostream>
#include <vector>

struct myclass {
    myclass() {
        std::cout << "Construct: " << this << std::endl;
    }

    myclass(const myclass& other) {
        std::cout << "Copy: " << this << std::endl;
    }

    void print() const {
        std::cout << "Print: " << this << std::endl;
    }
};

int main() {
    std::vector<myclass> v;

    v.reserve(10);

    for (uint32_t i = 0; i < 10; i++)
        v.push_back(myclass());

    std::cout << "\n";

    for (auto &x : v)
        x.print();

    return 0;
}

With output:

Construct: 0x7fffed870898
Copy: 0x7fffe5b3de70
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de71
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de72
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de73
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de74
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de75
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de76
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de77
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de78
Construct: 0x7fffed870898
Copy: 0x7fffe5b3de79

Print: 0x7fffe5b3de70
Print: 0x7fffe5b3de71
Print: 0x7fffe5b3de72
Print: 0x7fffe5b3de73
Print: 0x7fffe5b3de74
Print: 0x7fffe5b3de75
Print: 0x7fffe5b3de76
Print: 0x7fffe5b3de77
Print: 0x7fffe5b3de78
Print: 0x7fffe5b3de79

The emplace_back member function of std::vector may be used to construct objects in-place in a vector.

In the following we construct 5 temporaries which we can see reuse the same memory, and then we use push_back to place them in the vector.

Then we use emplace_back to construct five objects directly in the vector.

We can see that the memory address printed when the objects are created are the same as those printed later.

#include <iostream>                                                                                                                                                                                            
#include <vector>

struct myclass {
    myclass() {
        std::cout << "Construct: " << this << std::endl;
    }

    myclass(const myclass& other) {
        std::cout << "Copy: " << this << std::endl;
    }

    void print() const {
        std::cout << "Print: " << this << std::endl;
    }
};

int main() {
    std::vector<myclass> v;

    v.reserve(10);

    for (uint32_t i = 0; i < 5; i++)
        v.push_back(myclass());

    for (uint32_t i = 0; i < 5; i++) 
        v.emplace_back();

    std::cout << "\n";

    for (auto &x : v) 
        x.print();
        
    return 0;
}

Output:

Construct: 0x7fffc5e7d958
Copy: 0x7fffbd93fe70
Construct: 0x7fffc5e7d958
Copy: 0x7fffbd93fe71
Construct: 0x7fffc5e7d958
Copy: 0x7fffbd93fe72
Construct: 0x7fffc5e7d958
Copy: 0x7fffbd93fe73
Construct: 0x7fffc5e7d958
Copy: 0x7fffbd93fe74
Construct: 0x7fffbd93fe75
Construct: 0x7fffbd93fe76
Construct: 0x7fffbd93fe77
Construct: 0x7fffbd93fe78
Construct: 0x7fffbd93fe79

Print: 0x7fffbd93fe70
Print: 0x7fffbd93fe71
Print: 0x7fffbd93fe72
Print: 0x7fffbd93fe73
Print: 0x7fffbd93fe74
Print: 0x7fffbd93fe75
Print: 0x7fffbd93fe76
Print: 0x7fffbd93fe77
Print: 0x7fffbd93fe78
Print: 0x7fffbd93fe79

Upvotes: 56

Related Questions