AngryDuck
AngryDuck

Reputation: 4607

Creating multiple class objects with the same name? c++

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

Answers (2)

Matt Phillips
Matt Phillips

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

Some programmer dude
Some programmer dude

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

Related Questions