how to remove a shared ptr element from set? - c++

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;
}
}
}

Related

Cannot dereference end list iterator

I'm currently working on a project about browser histories. I'm using the STL's list implementation to keep track of the different websites. I have most of it figured out but I can't seem to resolve the error:
Screenshot; cannot dereference end list iterator.
The website data is contained within my Site objects.
class BrowserHistory {
private:
list<Site> history;
list<Site>::iterator current = history.begin();
public:
void visitSite(string, size_t)
void backButton();
void forwardButton();
void readFile(string);
};
void BrowserHistory::visitSite(string x, size_t y)
{
while (current != history.end()) {
history.pop_back();
}
history.push_back({ x, y });
current++;
}
void BrowserHistory::backButton()
{
if (current != history.begin())
current--;
}
void BrowserHistory::forwardButton()
{
if (current != history.end())
current++;
}
void BrowserHistory::readFile(string filename)
{
string action, url;
size_t pageSize;
ifstream dataIn;
dataIn.open(filename);
while (!dataIn.eof()) {
dataIn >> action;
if (action == "visit") {
dataIn >> url >> pageSize;
history.push_back({ url, pageSize });
current++;
}
if (action == "back") {
current--;
}
if (action == "forward") {
current++;
}
}
dataIn.close();
}
Can anyone explain to me what's wrong? Thanks in advance for any help.
When you initialise current, the list is empty.
Adding elements to the list does not suddenly make it a valid iterator, even though it will be different from end.
It looks like you're thinking of iterators as very much like pointers, but they're not.
Iterators are for iterating and should be considered transient, and not stored for later use.
Use a vector, and use an index for current instead of an iterator.
Further, I would rename the "button" functions (what does the history care about buttons?) to "goBack" and "goForward" and use your actual interface when reading:
void BrowserHistory::readFile(string filename)
{
ifstream dataIn(filename);
string action;
while (dataIn >> action) {
if (action == "visit") {
string url;
size_t pageSize;
if (dataIn >> url >> pageSize) {
visitSite(url, pageSize);
}
else {
// Handle error
}
}
else if (action == "back") {
goBack();
}
else if (action == "forward") {
goForward();
}
else {
// Handle error
}
}
}

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;});

How do I return a Null Pointer in a function C++

I am currently working on a bit of code that will search within a vector of type Person (which I have defined in the code and will show if needed). If it finds the person, it returns their name. This is currently working, but if it does not find the person, it is supposed to return a Null pointer. The problem is, I cannot figure out how to make it return a Null pointer! It just keeps either crashing the program every time.
Code:
Person* lookForName(vector<Person*> names, string input)
{
string searchName = input;
string foundName;
for (int i = 0; i < names.size(); i++) {
Person* p = names[i];
if (p->getName() == input) {
p->getName();
return p; //This works fine. No problems here
break;
} else {
//Not working Person* p = NULL; <---Here is where the error is happening
return p;
}
}
}
You could use std::find_if algorithm:
Person * lookForName(vector<Person*> &names, const std::string& input)
{
auto it = std::find_if(names.begin(), names.end(),
[&input](Person* p){ return p->getName() == input; });
return it != names.end() ? *it : nullptr; // if iterator reaches names.end(), it's not found
}
For C++03 version:
struct isSameName
{
explicit isSameName(const std::string& name)
: name_(name)
{
}
bool operator()(Person* p)
{
return p->getName() == name_;
}
std::string name_;
};
Person * lookForName(vector<Person*> &names, const std::string& input)
{
vector<Person*>::iterator it = std::find_if(names.begin(), names.end(),
isSameName(input));
return it != names.end() ? *it : NULL;
}
If the name you are searching for is not at the first element, then you are not searching in the rest of the elements.
You need to do something like -
for (int i = 0; i<names.size(); i++){
Person* p = names[i];
if (p->getName() == input) {
return p;
// Placing break statement here has no meaning as it won't be executed.
}
}
// Flow reaches here if the name is not found in the vector. So, just return NULL
return NULL;
As Chris suggested, try using std::find_if algorithm.
Looks like you just have to return Null, nullptr, or 0.
codeproject
Just use following code:
return NULL;

Cannot input correct element in C++ map container

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.

Why is std string == crashing?

When I run my application in debug mode, sometimes I get a runtime error in this function:
void ChatListHandler::seatOccupancyChanged( const std::string& userName, bool occupied, bool isSelf, bool isSelfTable, int tableNo, int seatNo, int numPlayersAtTable )
{
if(!isSelf && (isInGroup(userName,IN_GAME_GROUP) || isInGroup(userName,IN_LOBBY_GROUP)))
{
if(occupied)
{
movePlayer(userName,IN_GAME_GROUP);
}
else
{
movePlayer(userName,IN_LOBBY_GROUP);
}
}
}
bool ChatListHandler::isInGroup( const std::string& name, GroupTypeEnum group )
{
for(size_t i = 0; i < m_groups.size(); ++i)
{
if(m_groups[i].second == group)
{
if(m_groups[i].first->getList())
{
for(agui::ListItem::iterator it =
m_groups[i].first->getList()->getItemsBegin(); it !=
m_groups[i].first->getList()->getItemsEnd(); ++it)
{
if((*it).first.text == name)
{
return true;
}
}
}
break;
}
}
return false;
m_list->repositionGroups();
}
It crashes on:
if((*it).first.text == name)
I get:
Unhandled exception at 0x5fd1942c (msvcp90d.dll) in my.exe: 0xC0000005: Access violation reading location 0x00000040.
The call stack looks like:
Thanks
I can't be sure without seeing all the code, but my guess is that there error has to do with these lines:
for(agui::ListItem::iterator it =
m_groups[i].first->getList()->getItemsBegin(); it !=
m_groups[i].first->getList()->getItemsEnd(); ++it)
Unless your call to getList() is always returning exactly the same list every time (that is, a pointer to the same list, not a copy), you could be getting iterators over different lists. This would mean that the check it != m_groups[i].first->getList()->getItemsEnd() would always be false, since the iterators come from different lists. In that case, your iterator could walk off the end of the list, so the dereference would cause a crash.
Hope this helps!