I am relatively new to C . I tried to break down the problem.
All code is also here: https://onlinegdb.com/wAmLAONkF (can be executed)
Basically, I have a function where temp objects are created. The objects are pushed to a std::vector:
vector<Student> GetStudents(int some_params)
{
vector<Student> students;
//logic where students are returned
Student s1 { "John", 42 };
Student s2 { "Bill", 12 };
students.push_back(s1);
students.push_back(s2);
return students;
}
To maintain the objects, they are stored outside in a std::map.
The map stores each Student by pointer in a vector<Student*> (it has to be vector<Student*>!):
map<int, vector<Student*>> m {};
{ //start of new context, other class context in another file, map is passed by reference
int some_params = 5;
vector<Student> students = GetStudents(some_params);
To store them in the map, I copy references into a new vector:
vector<Student*> tmpV;
for(auto & student : students)
tmpV.push_back( &student);
//store them in the map
m.emplace(some_params, tmpV);
}//leave context
//data loss - Students are lost
I do know, that the problem is because the pointers to the objects are stored in a local vector. After I leave the context, the pointers do not point somewhere valid.
But how can I solve this?
CodePudding user response:
The vector<Student> returned by GetStudents() needs to be stored in a variable that is in the same scope as (or in a higher scope than) the std::map that refers to its Students, eg:
map<int, vector<Student*>> m;
vector<Student> students; // <-- move it up here!
{ //start of new context
int some_params = 5;
students = GetStudents(some_params);
vector<Student*> tmpV;
for(auto & student : students)
tmpV.push_back( &student);
//store them in the map
m.emplace(some_params, tmpV);
} //leave context
// no data loss - Students are valid!
Otherwise, GetStudents() will have to return a vector<Student*> instead, where each Student has been created dynamic via new, and then destroyed via delete after the map is done using them:
vector<Student*> GetStudents(int some_params)
{
vector<Student*> students;
//logic where students are returned
students.push_back(new Student{ "John", 42 });
students.push_back(new Student{ "Bill", 12 });
return students;
}
...
map<int, vector<Student*>> m;
{ //start of new context
int some_params = 5;
vector<Student*> students = GetStudents(some_params);
//store them in the map
m.emplace(some_params, students);
} //leave context
// no data loss - Students are valid!
...
for(auto &entry : m) {
for (auto *student : entry.second) {
delete student;
}
}
Ideally, your map should store either vector<Student> or vector<unique_ptr<Student>>, but your requirement of "it has to be vector<Student*>!" prevents that.
