Remove specific object from vector list - c++

I'm new to C++, sorry if it's a dummy question.
I'm trying to create a method that would remove a given pointer from a vector, and delete its object. Here's what I have right now:
void Engine::destroyObject(GameObject* obj) {
if (obj == nullptr) {
std::cout << "Error: GameObject pointer given is null!" << std::endl;
return;
}
else if (m_GameObjects.empty()) {
std::cout << "Error: Trying to destroy GameObject while list is empty!" << std::endl;
return;
}
auto it = std::remove(m_GameObjects.begin(), m_GameObjects.end(), obj);
if (it != m_GameObjects.end()) {
delete obj;
m_GameObjects.erase(it, m_GameObjects.end());
}
}
GameObject* Engine::findObject(std::string name) {
return *std::find_if(m_GameObjects.begin(), m_GameObjects.end(), [name](GameObject* e) { return e->getName() == name; });
}
I'm calling those methods like this:
GameObject* obj = findObject("Random");
destroyObject(obj);
But for some reason, my program crashes at m_GameObjects.erase(it, m_GameObjects.end()); with the error "vector iterator not dereferencable"
I have tried changing the line to it = m_GameObjects.erase(it, m_GameObjects.end()); but that did not change anything.
Thanks in advance!
Edit: Here's a bit more info
GameObject is just a regular class (with some data such as a name...)
The findProject method works fine, it's the line for erase that's causing an error.

So aschepler found out that my findObject function was not checking for null values (if the object didn't exist/couldn't be found) so I added some checks and it works now. Thanks a lot!
GameObject* Engine::findObject(std::string name) {
auto it = std::find_if(m_GameObjects.begin(), m_GameObjects.end(), [name](GameObject* e) { return e->getName() == name; });
if (it == m_GameObjects.end())
return nullptr;
return *it;
}
I then had to check if the value was a nullptr and not do anything if so.

Related

I want to combine the list and find(), but I don't know how to merge them

Please see the part where the find() function is called. (I ran it in Visual Studio.)
Code:
using namespace std;
int main(void) {
//Implementing the find()
/*
bool Find(const Stu & a); {
return (*it).name;
}
*/
list<Astu>::iterator that;
//that = astu.begin();
//that = find(astu.begin(), astu.end(), (*it).name);
for (it = stu.begin(); it != stu.end(); it++) {
that = find_if(astu.begin(), astu.end(), (*it).name);
if (that != astu.end()) {
all = astu.erase(all);
all++;
}
else
all++;
}
/*
//Filter absenteeism from the total student roster
for (it = stu.begin(); it != stu.end(); it++) {
for (all = astu.begin(); all != astu.end();) {
if (!strcmp((*all).name, (*it).name)) {
//Delete attendees and latecomers from the list
all = astu.erase(all);
}
else
all++;
}
}
*/
cout << "---------------------\n결석자: " << endl;
//이름순으로 정렬
astu.sort(SizeComp2);
//결석자들 출력
for (all = astu.begin(); all != astu.end(); all++) {
cout << "이름: " << (*all).name << endl;
}
return 0;
}
Output:
C2064 error occurred: Term does not evaluate to a function that takes
1 argument.
Even with find_if() in this code, there is a problem. The bool() part in the comment was used for the find_if object, but it doesn't seem to be used well here.
I deleted the part where there was no problem as a result of debugging. You must use an unconditional list, not a vector.
Where should I fix it?
The third argument to std::find_if is a function.
You could use a lambda as the function:
auto that = find_if(astu.begin(), astu.end(), [it](Astu const& astu)
{
return astu.name == it->name;
});
[This assumes that Astu::name is a std::string]

How to delete a node pointer

This is schoolwork. I haven't seen anything that really answers this directly, so I'm having a hard time fixing it. I have to create a linked node implementation of a max heap and I'm having difficulty with the deletion of a node after removing a value.
My Code:
template<class ItemType>
BinaryHeapNode<ItemType>* LinkedMaxHeap<ItemType>::getLastNode()
{
BinaryHeapNode<ItemType>* lastNode = rootPtr->getRightSiblingPtr();
BinaryHeapNode<ItemType>* prevLastNode = rootPtr;
while(lastNode != nullptr)
{
prevLastNode = lastNode;
lastNode = lastNode->getRightSiblingPtr();
}
return prevLastNode;
}
template<class ItemType>
bool LinkedMaxHeap<ItemType>::removeValue(ItemType value)
{
BinaryHeapNode<ItemType>* tempNode = rootPtr;
for (int i = 0; i < itemCount; i++)
{
if(tempNode->getItem() == value)
{
tempNode->setItem(getLastNode()->getItem());//set item
delete getLastNode(); //delete last node
getLastNode() = nullptr; //set last node null
getLastNode()->setRightSiblingPtr(nullptr); //last node should be different
itemCount--; //set it's sibling to null
heapRebuild(tempNode);
}
tempNode = tempNode->getRightSiblingPtr();
}
return true;
}
My issue is with getLastNode() = nullptr. VS is telling me that getLastNode() isn't an lvalue. That doesn't make sense to me because getLastNode is returning a pointer to a BinaryHeapNode, but it can't set that pointer to nullptr?
I thought this might be a problem with my logic of pointers (which is shaky at best) so I thought changing getLastNode() to return just a node would help. That did not. So I tried messing with the & operator and returning an address of the last node. Needless to say I haven't found the solution yet. If anyone can provide some sort of direction it would be appreciated. I'm just not entirely sure why it doesn't work.
EDIT:
Edited the code based on what arynaq mentioned. The errors went away, but now I have a bunch of linker errors I have to fix before I can test it. Will this code do what I want? I feel like it is just going to delete nodeToDelete and not get rid of the node in the heap.
template<class ItemType>
bool LinkedMaxHeap<ItemType>::removeValue(ItemType value)
{
BinaryHeapNode<ItemType>* tempNode = rootPtr;
BinaryHeapNode<ItemType>* nodeToDelete = getLastNode();
for (int i = 0; i < itemCount; i++)
{
if(tempNode->getItem() == value)
{
tempNode->setItem(nodeToDelete->getItem());
delete &nodeToDelete;
nodeToDelete = nullptr;
getLastNode()->setRightSiblingPtr(nullptr);
itemCount--;
heapRebuild(tempNode);
}
tempNode = tempNode->getRightSiblingPtr();
}
return true;
}
Ok, I'll try to help by explaining some things about pointers. Hopefully this will clarify some misconceptions and help you with your assignment.
When you get a copy of the pointer like so: mypointer* p = get_pointer(); and then you delete that, you are deleting the memory. But when you assign nullptr to this local variable, it wont affect the "source" of your pointer.
Here is a detailed example, showing where things can go wrong. If you never set v[0] to nullptr.
#include <iostream>
#include <vector>
struct Object {
~Object() {
std::cout << "Object destructor." << std::endl;
}
int val = 42;
};
struct OtherObj {
int val = 322;
};
void print_vec(const std::vector<Object*>& v) {
for (const auto& x : v) {
std::cout << x << std::endl;
}
}
int main(int, char**) {
// Init vector and print addresses.
std::vector<Object*> v(2);
print_vec(v);
// Init objects in vector and printit.
for (auto& x : v) {
x = new Object();
}
print_vec(v);
// Get a copy of a pointer and delete that. All good so far.
Object* pointer_to_delete = v[0];
delete pointer_to_delete;
// Assign nullptr to the temporary local pointer.
// Does nothing to the pointer in the vector.
pointer_to_delete = nullptr;
// Print the vector to prove it.
print_vec(v);
// On a non debug build, the memory will still have the last value.
// Careful! Cause of headaches here. This should be set to nullptr.
std::cout << v[0]->val << std::endl; // "No problem", certainly not nullptr.
// Now that we allocate a new object, v[0] will be overwritten.
OtherObj* bad_bad_boy = new OtherObj();
// Print the address of the new object, to show it was created at
// the old v[0] address.
std::cout << bad_bad_boy << std::endl;
// Bad things ensue...
std::cout << v[0]->val << std::endl;
return 0;
}
The output on clang is :
0x0
0x0
0x7ffa21c026c0
0x7ffa21c026d0
Object destructor.
0x7ffa21c026c0
0x7ffa21c026d0
42
0x7ffa21c026c0
322
As you can see, setting the local pointer to nullptr is not enough! I hope this clears up some things for you :)
Online version

exceptions and return statements in c++

I am new in c++ programming and i am trying to understand exceptions in c++. I made a simple model situation that shows things, which I don't understand(I hope, I wont mess up code too much). I made 2 basic classes with few methods(classes CPerson are basically linked list). My answer is how to stop current task with an exception. I am able to call an exception, but task continues and makes some mess in program.
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
using namespace std;
class CPerson{
public:
CPerson(){
p_next_person = NULL;
}
CPerson* p_next_person; // pointer to next person in linked list
int Postcode(); // returns postcode of person
friend ostream& operator<<(ostream& stream, const CPerson& pers){
cout << pers.ID << pers.postcode;
return stream;
}
char* ID;
int postcode;
};
//---------------------------------------------------------------
class CPeople{
public:
CPeople(){
first_person = NULL;
}
CPerson Person( const char* personID); // finds person by ID and returns it
bool NewPerson( const char* personID, int person_postcode); // add new person
CPerson* first_person ; // start of linked list
};
//-----------------------------------------------------------------
int CPerson::Postcode(){
return postcode;
}
//-----------------------------------------------------------------
CPerson CPeople::Person( const char* personID){
CPerson* now;
now = first_person;
while(now != NULL){
if(strcmp(now->ID,personID)==0){
break;
}
now = now->p_next_person;
}
// our person is in now (or now is NULL - if person wasn't found).
try{
if(now == NULL ){
throw 0;
// I need to stop code here
}else return *now;
}
catch (int e)
{
cout << "bla bla " << e << '\n';
}
}
//----------------------------------------------------------
int main(){
CPeople people;
int i = 0;
people.NewPerson( "JAck", 100 );
people.NewPerson( "Josh", 100 );
// Bob is not in people right now.
i = people.Person("BOB").Postcode();
cout << i;
// gives exception, which is nice. but it also changes i to some nonsence .. how do I fix it ?
cout << people.Person ( "BOB" );
// gives exception, which is nice. but also gives segmentation fault. how do I fix it ?
}
You have got the try block around 'throw. The try block should be around where you called the function and it should be caught with a catch. Thus your function will change to:
CPerson CPeople::Person( const char* personID){
CPerson* now;
now = first_person;
while(now != NULL){
if(strcmp(now->ID,personID)==0){
break;
}
now = now->p_next_person;
}
// our person is in now (or now is NULL - if person wasn't found).
if (now == NULL ){
throw 0;
// I need to stop code here
}
else return *now;
}
and main will look like:
int main(){
try {
CPeople people;
int i = 0;
people.NewPerson( "JAck", 100 );
people.NewPerson( "Josh", 100 );
// Bob is not in people right now.
i = people.Person("BOB").Postcode();
cout << i;
// gives exception, which is nice. but it also changes i to some nonsence .. how do I fix it ?
cout << people.Person ( "BOB" );
// gives exception, which is nice. but also gives segmentation fault. how do I fix it ?
}
catch (int e)
{
cout << "bla bla " << e << '\n';
}
}
Notice that once a catch is encountered, the following statement after the catch will be executed. That is why you should have catch out of the function definition.
Code like this
try{
if( now == NULL ){
throw 0;
// I need to stop code here
} else return *now;
} catch (int e) {
cout << "bla bla " << e << '\n';
}
entirely misses the point. Continuing execution with a shrug ("bla bla") as if nothing had happened isn't possible. Either you make sure that all contingencies are met in the catch, or you should catch the exception at a higher level. Here: there is no definition of the function's return value, which causes trouble up there where you call CPeople::Person.
You can surround these calls with a try - catch; omit them in the function and just throw.
Don't throw 0. Use an object capable of holding some information. Throw by value, catch by reference.

Calling delete causes C++ program to freeze

void FactorySystem::deleteObjectsToBeDeleted()
{
//Delete all objects in the ObjectsToBeDeleted list
std::vector<unsigned>::iterator it = objectsToBeDeleted.begin();
for(unsigned i = 0; i < objectsToBeDeleted.size(); i++)
{
GameObjectIDMapType::iterator it = gameObjectIDMap.find(objectsToBeDeleted[i]);
if(it == gameObjectIDMap.end())
std::cout << "Bad memory or double deletion error!" << std::endl;
else
{
//Delete it and remove its entry in the ID map
std::cout << (it->second->GetID()) << std::endl;
GameObject *object = it->second;
delete object;
gameObjectIDMap.erase(it);
}
}
//All objects to be delete have been deleted
objectsToBeDeleted.clear();
}
At the line where I call delete object, the program just hangs forever, and I can not figure out why. I have googled this problem and it's like nobody has ever encountered this problem ever. I must be doing something bad, but I have no idea what it could be. Any ideas? Thanks.
EDIT:
I was asked to show the destructor for GameObject, here it is:
GameObject::~GameObject()
{
//Delete each component using the component's virtual destructor
//takes care of all resources and memory.
for( ComponentMapIt it = componentMap.begin();it!=componentMap.end();++it)
delete it->second;
}
One other thing to not, I went into the disassembly and was able to step up until:
00488DA9 call GameObject::`scalar deleting destructor' (044055Fh)
and then it just hangs, nothing else happens.
EDIT: Here was my rookie mistake. For some reason I couldn't step into the delete call so I assumed it was in there, but putting a break point in it allowed me to go into it. Thanks everyone, all your suggestions were very helpful.
void PhysicsManager::Unregister(RigidBody *Obj)
{
std::list<RigidBody*>::iterator it = MasterList.begin();
while(it != MasterList.end())
{
if(*it == Obj)
{
MasterList.erase(it);
return;
}
}
}
void PhysicsManager::Unregister(RigidBody *Obj)
{
std::list<RigidBody*>::iterator it = MasterList.begin();
while(it != MasterList.end())
{
if(*it == Obj)
{
MasterList.erase(it);
return;
}
}
}
it is constant and never changes: once the loop start and *it != Obj the loop continues forever

STL list<mystruct> return problem

I am trying to use STL list in a project but i have the following problem.
I want my list to store a struct. For example this one
struct mystruct
{
int x;
int y;
};
Then i am using an iterator to access every struct in the list like this.
list<mystruct> L;
list<mystruct>::iterator lit;
for(lit=L.begin();lit!=L.end();lit++)
{
if(lit->x==1) cout << "<NUM," << lit->x << "> ";
if(lit->y==2) cout << "<ID," << lit->y << "> ";
}
This works but i want to get one struct at a time so i made this func
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
but i get an error after running it and i cannot understand why this happens.
Any ideas what is going wrong?
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
You increment unless you already are at the end, but the dereferencing happens every time, regardless of if you are at the end or not. To help around that problem, consider returning a pointer, and then a 0 pointer if you are at the end.
mystruct* Myclass::next(void)
{
if(lit!=L.end() && ++lit != L.end())
{
// dereference to get the struct, and then return the address of the struct
return &*lit;
}
return 0;
// or nullptr in C++0x
}
And then check agains 0 (or nullptr) in the code where you use Myclass::next.
If you're writing next() that returns an object (rather than pointer), then I think you also need to write has_next() function which you should call to inspect if there is item in the list or not, before calling next(). Something like this:
bool has_next()
{
list<mystruct>::iterator temp = lit;
return ++temp != L.end();
}
mystruct Myclass::next(void)
{
if( !has_next())
{
throw "end of the list is reached";
}
++lit;
return *lit;
}
//usage
while(myClassInstance.has_next())
{
mystruct s = myClassInstance.next();
//work with s
}
Or if you decide to return pointer to mystruct from next(), then has_next() is not so needed. You can write this:
mystruct * Myclass::next(void)
{
++lit;
if( lit == L.end() )
return NULL;
return &(*lit);
}
The problem is here :
mystruct Myclass::next(void)
{
if(lit!=L.end())
{
lit++;
}
return *lit;
}
First how is lit defined?
Second, if lit is equal to L.end() you should return some default value, not dereference it, because if you do, you are causing an undefined behaviour. If you are lucky, your program will crash.