c++pointersthis

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?


Solution

  • 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.

    #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