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 Student
s, 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.