Reputation: 4607
I'm making an application that is querying a MySQL database.
I want the results of this to be stored in a map (which has a corresponding pair):
std::map<int, Car*> m_car;
typedef std::pair<int, Car*> m_car_pair;
The car object is made up of 8 parameters, one of which is car_id so firstly I pull the car ID and use it as the key then I want to store the entire car object as the value of the map. (I know this is casing me to be storing the car_id twice but for the moment I don't mind that).
Anyway here's my query code:
void DatabaseController::getAll(QString query_string)
{
// Console log message
std::cout << "Querying Database" << std::endl;
/// Declare SQL query and pass function parameter 'query'
QSqlQuery query(query_string);
// execute the query
query.exec();
int count = 0;
// While results are coming in
while(query.next())
{
// Call car constructor passing all parameters
Car car(query.value(count).toInt(), query.value(count+1).toString(), query.value(count+2).toString(), query.value(count+3).toString(),
query.value(count+4).toInt(), query.value(count+5).toInt(), query.value(count+6).toInt(), query.value(count+7).toString());
if (car.getcarID() != 0)
{
m_car_records.insert(m_car_pair(car.getcarID(), &car));
}
}
std::cout << "Database query finished" << std::endl;
After this I made a quick test function to iterate over the map and pull all of the ID's (map key) and check they were different (i.e. the function worked) and they were.
But that was just a check what I needed was to be able to call the accessory functions from car on the car objects that should be in the map. So I used the same quick test function to iterate over the map and cout << car.toString();
(a simple to string function in the car class):
void DatabaseController::test()
{
m_car_records_iterator = m_car_records.begin();
for(unsigned int i = 0; i < m_car_records.size(); i++)
{
car *test = m_car_records_iterator->second;
std::cout << test->toString() << std::endl;
m_car_records_iterator++;
}
}
This showed the correct number of results however they all were the same i.e. the car object that has been added to every entry in the map is the same (the values of the last record that was found by the query)
My Question is...
Is there any way that using this structure I currently have for my query I can create and add these class objects to my map within the while loop using the same name for each, because of course I can't know how many results are being returned and declare a class object for each one, but as it stands using the same name is just adding the same one every time not actually replacing the values... at least that's what I think is happening??
Any advice or idea would be welcomed (sorry for the long post)
Upvotes: 0
Views: 3332
Reputation: 9691
This is your problem--
Car car( ... ); // ***Stack allocated
if (car.getcarID() != 0)
{
m_car_records.insert(m_car_pair(car.getcarID(), &car));
}
//But the pointer is what's stored
When the loop iterates, the Car
instance is destroyed and the pointer dangles, resulting in undefined behavior. You need
Car* car = new Car( ... );
and then when m_car
is no longer needed, you need to iterate through and delete
its Car
values.
Upvotes: 2
Reputation: 409136
You are experiencing undefined behavior. The reason is that you insert a pointer to a local variable in the map.
In the loop in getAll
, when the loop starts over on the next item the car
variable is not valid any more.
I suggest you look into std::shared_ptr
for the pointers.
Upvotes: 2