问题
I have an object that I am trying to duplicate for any number of times with some minor changes to that object. I want to store pointers to those duplicated objects in a std::vector
. I am using a for
loop to try and achieve the result. However, what I notice is that the std::vector<T *>
is pointing to the same address after the loop exits. I tried this attempt to duplicate objects with std::string
and I see the same effects. Here's my code snippet.
int main() {
auto name = new std::string("fido");
const int size = 3;
std::vector<std::string *> names;
names.reserve(size);
for (int i = 0; i < size; i++) {
std::string n = *name + " " + std::to_string(i);
names.push_back(&n);
}
// nothing from this loop prints out
for (auto n : names) {
std::cout << *n << std::endl;
}
return 0;
}
When I place the code in a debugger, I see that names
is storing pointers all to the same memory address: 0x7ffffffeead0
. Any ideas on what I am doing wrong here?
I modified the code to store a vector of strings, and then to loop through each string, creating a pointer to each string's address as follows. This approach also does not work. The vector of pointers all still point to the same address; although this time, they all point to the address of the last string.
int main() {
auto name = new std::string("fido");
const int size = 3;
std::vector<std::string *> pointers;
std::vector<std::string> names;
names.reserve(size);
pointers.reserve(size);
for (int i = 0; i < size; i++) {
std::string n = *name + " " + std::to_string(i);
names.push_back(n);
}
for (int i = 0; i < size; i++) {
auto n = names.at(i);
auto p = &n;
pointers.push_back(p);
}
for (auto n : names) {
std::cout << n << std::endl;
}
for (auto n : pointers) {
std::cout << *n << std::endl;
}
return 0;
}
Yet, in a third attempt, I modify the code as follows. Note that I use the &
operator against where I access the element by index. Here, I do get a std::vector<std::string *>
that points to different addresses (corresponding correctly to the vector of strings).
int main() {
auto name = new std::string("fido");
const int size = 3;
std::vector<std::string *> pointers;
std::vector<std::string> names;
names.reserve(size);
pointers.reserve(size);
for (int i = 0; i < size; i++) {
std::string n = *name + " " + std::to_string(i);
names.push_back(n);
}
for (int i = 0; i < size; i++) {
auto p = &names.at(i); // using address operator like this "works"
pointers.push_back(p);
}
for (auto n : names) {
std::cout << n << std::endl;
}
for (auto n : pointers) {
std::cout << *n << std::endl;
}
return 0;
}
Lastly, I finally get this more concise example to work. Here, I create a new pointer on every loop.
int main() {
auto name = new std::string("fido");
const int size = 3;
std::vector<std::string *> names;
names.reserve(size);
for (int i = 0; i < size; i++) {
auto x = new std::string(*name + " " + std::to_string(i));
names.push_back(x);
}
for (auto n : names) {
std::cout << *n << std::endl;
}
return 0;
}
Is there something on for-loops
and pointers that I am missing here? Any pointers (no pun intended) to scoping rules for C++ would be appreciated.
回答1:
However, what I notice is that the std::vector is pointing to the same address after the loop exits.
Any ideas on what I am doing wrong here?
for (int i = 0; i < size; i++) { std::string n = *name + " " + std::to_string(i);
Here, n
is an automatic variable. n
- like all objects with automatic storage, will be destroyed at the end of the scope, i.e. at the end of the iteration.
names.push_back(&n);
Here, you take the address of the automatic object and store it inside a vector.
}
Here, the iteration ends and the next one begins. n
has been destroyed and the pointer in the vector is invalid. In the next iteration, a new n
object is created. Since the previous n
was destroyed, the same memory can be used for the next object.
for (auto n : pointers) { std::cout << *n << std::endl;
On this line, you attempt to access non-existing string through an invalid pointer and the behaviour of the program is undefined.
The same pattern persists through your second and third attempt.
In all your examples including the fourth one, you leak memory.
I have an object that I am trying to duplicate for any number of times
You can store strings in std::vector<std::string>
. You can duplicate such vector like this:
std::vector<std::string> names;
// insert names here
std::vector<std::string> duplicates = names;
来源:https://stackoverflow.com/questions/60254864/creating-pointers-inside-a-for-loop-results-in-pointing-to-same-memory-address