Cannot input correct element in C++ map container - c++

I've got the code:
string key = "", value = "", type = "";
while(in)
{
getline(in, key, '=');
getline(in, value, '\n');
getline(in, type, '\n');
in.get(); // get the dividing empty line
CommonParamValue *paramValue = CreateParamValue(type);
paramValue->SetValue(value);
params.insert(make_pair(key, *paramValue)); // PROBLEM
delete paramValue;
}
When I call params.insert(make_pair(key, *paramValue)); I get an element of map with correct key end EMPTY value. When I check
paramsIter = params.find(paramKey);
if (paramsIter != params.end())
{
if( ("" == paramsIter->second.GetValue())
...
}
All the time condition "" == paramsIter->second.GetValue() is true, but it must not be so!
Additional information:
class CommonParamValue
{
public:
virtual void SetValue(string value){}
virtual string GetValue(){ return ""; }
};
class StringParamValue : public CommonParamValue
{
string str;
public:
StringParamValue(){}
virtual void SetValue(string value){str = value;}
virtual string GetValue() {return str;}
};
CommonParamValue* Report::CreateParamValue(const string &strType) const
{
if (strType == "int")
{
return (new IntParamValue());
}
else if(strType == "string")
{
return (new StringParamValue());
}
else
{
// error
exit(1);
}
}
The question is why when I do params.insert(make_pair(key, *paramValue)); I always get an element with correct key and an EMPTY value? What is wrong?

I suspect the map is declared as:
std::map<std::string, CommonParamValue> params;
The insertion will result in the slicing of the value, to a CommonParamValue which always returns a "" from GetValue(). To obtain the desired behaviour the value would in the map would need to be a pointer to a CommonParamValue, preferably a smart pointer:
std::map<std::string, std::shared_ptr<CommonParamValue> > params;

The object inserted into the map is a CommonParamValue not a StringParamValue, that means that the copy of your objects inserted into the map get sliced to CommonParamValue.
Change your map definition to have a (smart) pointer or reference mapped.

Related

How to pass array of object pointers to function?

I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}

C++ OOP, blank console when outputting vector of object pointers, unsure if populated vector correctly

I have a csv file where I'm trying to store the information within a vector of object pointers.
I have a Item class which stores the name and price from the csv file.
class Item
{
private:
std::string name;
float price;
public:
std::string getName() { return name; }
float getPrice() { return price; }
void setName(std::string newName) { name = newName; }
void setPrice(float x) { price = x; }
};
I have a function that updates the fields of instances of that object
Item* addItem(const std::string& name, float price)
{
Item* obj = new Item();
obj->setName(name);
obj->setPrice(price);
items.push_back(obj);
return obj;
};
Main code:
global vector
std::vector<Item*> items;
int main()
{
// CSV file:
//1 Nachos,4.99,
//2 Buffalo wings,3.99,
// ...
// Open file into data var
std::ifstream data("menu.csv");
// Store data in str
std::string str;
while (getline(data, str))
{
std::istringstream iss(str);
// values to collect
std::string name, price;
getline(iss, name, ',');
getline(iss, price, ',');
// push_back to items vector using class function
addItem(name, std::stof(price));
}
data.close();
// output vector contents
for (int i = 0; i < items.size(); i++)
{
std::cout << items[i]->Item::getName() << items[i]->Item::getPrice() << std::endl;
}
return 0;
}
The problem I am having is that when I try to output the code, i get a blank console and am not sure whether the problem lies within the population of the vector or with the method of which i am trying to output the contents of the vector. I'm not sure whether it is a scope problem or not...
Does anyone see where I could be going wrong?
Couple of things to check for:
Check if the file has opened correctly. Use the is_open() function like data.is_open();
Don't use Item* in vector, just use Item.
In the function addItem, you are returning an object pointer and never assigning to any pointer in main. There is no need to return anything from that function. You are adding the object to the vector in the function itself.

how to remove a shared ptr element from set?

I have a set where each element in the set is of type shared_ptr, I want to remove an element from the set, in eclipse the element was actually removed but when I test this in bash with valgrind I get a lot of invalid size mistakes ...
So this made me think that maybe there is a different way to remove element of type shared_ptr ?
Every element in the peoplePointer is a class of certain person:
typedef std::shared_ptr<person> peoplePointer;
class AA {
std::set<peoplePointer> setOfPeople;
public:
// function getName() return name of the person (person is another class)
void removeSomeonefromA(const std::string& name) {
for (std::set<peoplePointer>::iterator it = setOfPeople.begin();it != setOfPeople.end(); it++) {
if(name == (*it).get()->getName()) {
setOfPeople.erase((it));
}
}
}
};
Idea inspired by remove_if equivalent for std::map.
If you are able to use a C++11 or later compiler, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
it = setOfPeople.erase(it);
}
else
{
++it;
}
}
}
If you are required to use a prior compiler version, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
setOfPeople.erase(it++);
}
else
{
++it;
}
}
}

Remove object from list based on object property

my code is:
class Room {
public:
int id;
string name;
int ownerFd;
Room(int id, string name, int ownerFd)
{
this->id = id;
this->name = name;
this->ownerFd = ownerFd;
}
};
void RemoveUserRooms(int ownerFd) {
for(auto& room : rooms) {
if (room.ownerFd == ownerFd) {
//remove room from list
}
}
}
What I want to do is to remove object from list. I already tried with remove and erase but that seems not to work in this way. Is is possible to do with list?
Use iterator and erase while properly updating the iterator.
for(auto i=rooms.begin();i!=rooms.end();)
{
if((*i).ownerFd == ownerFd)
i=rooms.erase(i);
else
i++;
}
Or better ,
you can use remove_if
rooms.remove_if([ownerFd](Room i){return i.ownerFd == ownerFd;});

Deleting the object that a pointer in a vector of pointers points to

I have a vector of pointers that point to dynamically allocated Martian structs. My add function seems to work fine but I'm afraid of my delete function not doing a proper delete of the object and pointer. Could you guys look through the delete function and tell where i would fix the problem?
struct Martian
{
string fname, lname, ssid;
Martian(string fname, string lname, string ssid) : fname(fname), lname(lname), ssid(ssid){}
};
class martianDatabase
{
public:
vector<Martian*> database;
martianDatabase();
void deleteMartian(string deletedID);
void addMartian(int &i, string f, string l, string id);
int iterator = 0, size = 0;
};
void martianDatabase::addMartian(int& i, string f, string l, string id)
{
this->database.push_back(new Martian(f, l, id));
i++;
}
void martianDatabase::deleteMartian(string deleteID)
{
int i = 0;
while (i < size +1)
{
if (this->database[i]->ssid == deleteID){
delete this->database[i];
size--;
break;
}
else ++i;
}
}
This deletes all Martian objects with matching ssid values.
void martianDatabase::deleteMartian( string deleteID )
{
auto martianIterator = database.begin();
while( martianIterator != database.end() )
{
if( (*martianIterator)->ssid == deleteID )
{
delete *martianIterator;
martianIterator = database.erase( martianIterator );
}
else
{
++martianIterator;
}
}
}
By calling delete on a pointer you will free the memory space used by the pointed object (in fact the memory will not be freed, but let say it will be reusable).
The problem you will encounter with your program is that you delete your entry, then reduce your vector's size, but the pointer is not removed and not set to nullptr, which means you will have issues when trying to dereference it (your code will only work if you delete the last element).
Also, you could (should ?) use the new smart pointers introduced by c++11, in your case you could replace your raw pointers with std::shared_ptr.
For more information:
http://en.cppreference.com/w/cpp/memory/shared_ptr