I am writing a function that creates a vector of Product objects from .csv file data and emplaces the object pointer value into a map with its corresponding Product ID as the key. When I run a test that should print each objects attributes from the map, I get a runtime error std::bad_alloc.
Here's the code:
#include <string>
#include <map>
#include <vector>
#include <fstream>
#include <iostream>
#include <sstream>
class Product {
private:
std::string productID;
std::string productName;
double productPrice;
public:
Product(std::string id, std::string name, double price) {
productID = id;
productName = name;
productPrice = price;
}
std::string getProductID() {
return productID;
}
std::string getProductName() {
return productName;
}
double getProductPrice() {
return productPrice;
}
};
class Reader {
public:
static std::vector<std::vector<std::string>> readCSV(std::string fileName) {
std::vector<std::vector<std::string>> content;
std::vector<std::string> row;
std::string line, word;
std::fstream file (fileName, std::ios::in);
if (file.is_open()) {
while (getline(file, line)) {
row.clear();
std::stringstream str(line);
while(getline(str, word, ',')) {
row.push_back(word);
}
content.push_back(row);
}
} else {
std::cout << "Could not open the file" << std::endl;
}
return content;
}
};
std::map<std::string, Product*> loadProductMap(std::string fileName) {
std::vector<std::vector<std::string>> productMapFile = Reader::readCSV(fileName);
std::vector<Product> products;
std::map<std::string, Product*> productMap;
for (size_t i = 0; i < productMapFile.size(); i++) {
products.emplace_back(productMapFile.at(i).at(0), productMapFile.at(i).at(1), stod(productMapFile.at(i).at(2)));
productMap.emplace(products.at(i).getProductID(), &products.back());
}
return productMap;
}
int main() {
std::map<std::string, Product*> productMap = loadProductMap("product_list.csv");
for (auto &i : productMap) {
std::cout << i.second->getProductID() << " " << i.second->getProductName() << " " << i.second->getProductPrice() << std::endl;
}
return 0;
}
Here is product_list.csv:
Meat01,T-Bone Steak,7.99
Meat02,Tyson Fresh Chicken Wings,10.00
Icecream01,Chocolate Ice Cream,2.50
Iceceam02,Vanilla Ice Cream,2.50
Corn01,Fresh Sweet Corn,2.00
Casewater01,24 Bottles 16-Oz of Deer Park Water,4.99
Potatochips01,Plain Potato Chips,2.00
Potatochips02,Green Onion Potato Chips,2.00
Donuts01,Glazed Donuts One-Dozen,4.99
Saugage01,8-Sausage Pack,4.99
Eggs01,Dozen Eggs,3.00
Milk01,Gallon Milk,4.00
The output:
4.99
2
Donuts01 �SRm�U�ce-Dozen 4.99
Eggs01 Dozen Eggs 3
2.5
2.5
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Aborted
Expected output:
Meat01 T-Bone Steak 7.99
Meat02 Tyson Fresh Chicken Wings 10
Icecream01 Chocolate Ice Cream 2.5
Iceceam02 Vanilla Ice Cream 2.5
Corn01 Fresh Sweet Corn 2
Casewater01 24 Bottles 16-Oz of Deer Park Water 4.99
Potatochips01 Plain Potato Chips 2
Potatochips02 Green Onion Potato Chips 2
Donuts01 Glazed Donuts One-Dozen 4.99
Saugage01 8-Sausage Pack 4.99
Eggs01 Dozen Eggs 3
Milk01 Gallon Milk 4
After inserting a breakpoint, I noticed that products.emplace_back() seemingly works correctly, and then productMap.emplace() works correctly, but then on the loop back around, the creation of the second Product object from products.emplace_back() wipes the previous Product's attribute data inside the map. The productMap.emplace() then works correctly again, copying over the new Products data... and so on...
After the first product is added to the map, but before the second product is created in the vector
After the second product is created in the vector
I've tried changing products.emplace_back to the push_back method and productMap.emplace to the insert method. Also, I tried breaking the loop down into two separate loops like this:
for (auto productData : productMapFile) {
products.emplace_back(productData.at(0), productData.at(1), productData.at(2));
}
for (auto product : products) {
productMap.emplace(product.getProductID(), &product);
}
What is causing this? I'd love to understand it more. A work around is fine too.