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?
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