Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use existing object in vector or create new if not exists in C++

Tags:

c++

pointers

Let's assume that I have a class named Store which contains products. Functions are inlined for simplicity.

class Store
{
public:
    Store(string name)
        : _name(name)
    {}

    string getName() const
    { return _name; };

    const std::vector<string> getProducts()
    { return _products; };

    void addProduct(const string& product)
    { _products.push_back(product); }

private:
    const string _name;
    std::vector<string> _products;
};

Then I have a two dimensional string array which contains store-product -pairs. Same store can be multiple times in array.

string storeListing[4][2] = {{"Lidl", "Meat"},
                             {"Walmart", "Milk"},
                             {"Lidl", "Milk"},
                             {"Walmart", "Biscuits"}};

Now I want to iterate through array, create Store-object for each store in array and add products of it to object. So I need to use existing Store-object or create a new if there is no any with correct name yet. What is a way to implement this? Currently I'm trying to use pointer and set it to relevant object, but I'm getting sometimes segmentation faults and sometimes other nasty problems when I modify code slightly. I guess I'm calling some undefined behavior here.

std::vector<Store> stores;
for (int i = 0; i < 4; ++i) {
    string storeName = storeListing[i][0];
    string productName = storeListing[i][1];

    Store* storePtr = nullptr;
    for (Store& store : stores) {
        if (store.getName() == storeName) {
            storePtr = &store;
        }
    }

    if (storePtr == nullptr) {
        Store newStore(storeName);
        stores.push_back(newStore);
        storePtr = &newStore;
    }

    storePtr->addProduct(productName);
}
like image 522
Paulus Limma Avatar asked Jan 01 '26 10:01

Paulus Limma


1 Answers

Most likely, because you insert "Store" copies into your vector:

if (storePtr == nullptr) {
    Store newStore(storeName);   //create Store on stack
    stores.push_back(newStore);  //Make a COPY that is inserted into the vec
    storePtr = &newStore;       // And this is where it all goes wrong.
}

newStore goes out of scope at the end of the if and StorePtr is lost.

Try it with:

storePtr = stores.back();

Or make your vector a std::vector<Store*>.

And then:

if (storePtr == nullptr) {
Store * newStore = new Store(storeName);   //create Store on stack
stores.push_back(newStore);  //Make a COPY that is inserted into the vec
storePtr = newStore;       // And this is where it all goes wrong.
}

And of course, as the comments suggest, a std::map would be better suited here.

In short, std::map stores key-value pairs. The key would most likely be your store name, and the value the product.

Quick example:

std::map<std::string, std::string> myMap;
myMap["Lidl"] = "Milk";
myMap["Billa"] = "Butter";
//check if store is in map:
if(myMap.find("Billa") != myMap.end())
  ....

Note, you can of course use your Store object as value. To use it as key, you have to take care of a few things:

std::maps with user-defined types as key

For your specific example i would suggest you use a std::string as key, and a vector of Products as value.

like image 183
Hafnernuss Avatar answered Jan 03 '26 10:01

Hafnernuss



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!