I have a list where I store a pointer to a pointer of objects. I have a function where I create pointers to these objects and store their addresses in the list (hence pointer to a pointer). However once this function is done that pointer is no longer valid (the object is but not the pointer because it's out of scope) so now my pointer to pointer doesn't work. How do you get around this?
list<Actor**> lst;
void CreateEnemy()
{
Actor* a = new Actor();
lst.push_back(&a);
}
int _tmain(int argc, _TCHAR* argv[])
{
CreateEnemy();
// at this point the pointer to a pointer stored in lst isn't valid anymore because it went out of scope after CreateEnemy() completed.
}
Here's a simple example of something you could do based on your comments.
list<unique_ptr<Actor>> lst;
void CreateEnemy()
{
lst.push_back(unique_ptr<Actor>(new Actor));
}
void KillRandomEnemies()
{
for (auto& i : lst)
{
if (rand() % 100)
i.reset();
}
}
class Projectile
{
public:
Projectile(unique_ptr<Actor> & a)
:actor(&a)
{}
bool IsTargetDead() const { return !(*actor); }
private:
unique_ptr<Actor> * actor;
};
int main()
{
CreateEnemy();
Projectile proj(lst.front());
while (something())
{
KillRandomEnemies();
if (proj.IsTargetDead())
whatever();
}
}
Just use std::list<Actor*> and store the pointer. Or, even better, std::list<Actor>. There's nothing here that suggests a need for any pointers, much less a pointer to a pointer.
Try this :
after the call to createEnemy :
Actor * a = * lst.front();
a -> some function.
Is this still doing problems?
I tested the code on my own class and it was fine.
Related
I come from C/C# language and now I'm trying to learn about C++ and his standards functions.
Now, I'm creating a class called IMonsterDead. I will have a std::vector<IMonsterDead*> with N monsters.
Example:
class IMonsterDead {
public:
IMonsterDead(int Id)
{
this->_Id = Id;
}
virtual void OnDead() = 0;
int Id() const {
return _Id;
}
private:
int _Id;
};
One class which implements that class:
class MonsterTest : public IMonsterDead {
public:
MonsterTest(int generId)
: IMonsterDead(generId)
{
}
virtual void OnDead()
{
std::cout << "MonsterTesd died" << std::endl;
}
};
Ok, if I access directly everything works fine. But I'm trying to use std::find.
Full program test:
int main()
{
std::vector<IMonsterDead*> monsters;
for (int i = 0; i < 1000; i++)
{
monsters.emplace_back(new MonsterTest(1000 + i));
}
int id = 1033;
std::vector<IMonsterDead*>::iterator result = std::find(monsters.begin(), monsters.end(), [id]( IMonsterDead const* l) {
return l->Id() == id;
});
if (result == monsters.end())
std::cout << "Not found" << std::endl;
else
{
// Here I want to access OnDead function from result
}
return 0;
}
So I need to access OnDead function from result but I can't. Intellisense doesn't show anything for me. The result exists.
How can I access that function? Have another better way to do that?
You need to use std::find_if() instead of std::find(). std::find() is for finding an element with a specific value, so you have to pass it the actual value to find, not a user_defined predicate. std::find_if() is for finding an element based on a predicate.
Either way, if a match is found, dereferencing the returned iterator will give you a IMonsterDead* pointer (more accurately, it will give you a IMonsterDead*& reference-to-pointer). You need to then dereference that pointer in order to access any members, like OnDead().
You are also leaking memory. You are not delete'ing the objects you new. And when dealing with polymorphic types that get deleted via a pointer to a base class, the base class needs a virtual destructor to ensure all derived destructors get called properly.
With that said, you are clearly using C++11 or later (by the fact that you are using vector::emplace_back()), so you should use C++11 features to help you manage your code better:
You should use std::unique_ptr to wrap your monster objects so you don't need to delete them manually.
You should always use the override keyword when overriding a virtual method, to ensure you override it properly. The compiler can catch more syntax errors when using override than without it.
You should use auto whenever you declare a variable that the compiler can deduce its type for you. Especially useful when dealing with templated code.
Try something more like this:
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
class IMonsterDead {
public:
IMonsterDead(int Id)
: m_Id(Id)
{
}
virtual ~IMonsterDead() {}
virtual void OnDead() = 0;
int Id() const {
return m_Id;
}
private:
int m_Id;
};
class MonsterTest : public IMonsterDead {
public:
MonsterTest(int generId)
: IMonsterDead(generId)
{
}
void OnDead() override
{
std::cout << "MonsterTest died" << std::endl;
}
};
int main()
{
std::vector<std::unique_ptr<IMonsterDead>> monsters;
for (int i = 0; i < 1000; i++)
{
// using emplace_back() with a raw pointer risks leaking memory
// if the emplacement fails, so push a fully-constructed
// std::unique_ptr instead, to maintain ownership at all times...
monsters.push_back(std::unique_ptr<IMonsterDead>(new MonsterTest(1000 + i)));
// or:
// std::unique_ptr<IMonsterDead> monster(new MonsterTest(1000 + i));
// monsters.push_back(std::move(monster));
// or, if you are using C++14 or later:
// monsters.push_back(std::make_unique<MonsterTest>(1000 + i));
}
int id = 1033;
auto result = std::find_if(monsters.begin(), monsters.end(),
[id](decltype(monsters)::value_type &l) // or: (decltype(*monsters.begin()) l)
{
return (l->Id() == id);
}
// or, if you are using C++14 or later:
// [id](auto &l) { return (l->Id() == id); }
);
if (result == monsters.end())
std::cout << "Not found" << std::endl;
else
{
auto &monster = *result; // monster is 'std::unique_ptr<IMonsterDead>&'
monster->OnDead();
}
return 0;
}
Iterators are an interesting abstraction, in this case to be reduced to pointers.
Either you receive the pointer to the element or you get an invalid end.
You can use it as a pointer: (*result)->func();
You can also use it to create a new variable:
IMonsterDead &m = **result;
m.func();
This should give the same assembly, both possible.
I'm starting to get a grasp on pointers and avoiding memory leaks...
I have one question though... Before I begin, I am NOT using C++11 so please don't reply with information on smart pointers and such that are specific to C++11...
I have the following code...
class Test
{
public:
Test(const int s_id, const std::string s_name) :
id(s_id),
name(s_name)
{
};
const int GetID()
{
return id;
}
private:
const int id;
const std::string name;
};
class TestCollection
{
public:
void AddTest(Test& my_test)
{
tests[my_test.GetID()] = &my_test;
}
void RemoveTest(const int id)
{
if (tests.find(id) != tests.end())
{
tests.erase(id);
}
}
public:
std::map<int, Test*> tests;
};
int _tmain(int argc, _TCHAR* argv[])
{
TestCollection collection;
Test my_test(0, "First Test");
collection.AddTest(my_test);
collection.RemoveTest(0);
return 0;
}
My question is do I need to do anything else to clear up the memory from my_test when I call RemoveTest? So as to avoid a memory leak?
I know that when I use the new keyword I need to call delete... But what do I do in this case?
Does it just get auto cleaned up by the garbage collector?
In the example both collection and my_test are allocated on the stack. As soon as the scope ends(return from _tmain) the memory will be released.
Taking pointers of stack variables that can exist outside the variable scope will result in unpredictable behavior. In this case if collection takes the object and stores the pointer rather than a copy.
So, I've found myself doing this a lot, and wonder if it's correct practice (this probably won't compile - I'm writing this on my phone):
class Shared
{
private:
int _x;
public:
void X(int newValue) { _x = newValue; }
int X() { return _x; }
Shared(void) : _x(0)
{
}
};
class Owner
{
private:
shared_ptr<Shared> _shared;
public:
const Shared& Shared() const
{
return *_shared;
}
void Shared(const Shared& newValue)
{
_shared.reset(&newValue);
}
void DoSomethingWithShared()
{
/// yeah, this could be cleaner, not the point!
_shared.X(_shared.X() + 1);
}
};
void CreateStuff(Owner& a, Owner &b)
{
Shared s;
a.Shared(s);
b.Shared(s);
}
int main(int argc, char *argv[])
{
Owner a;
Owner b;
CreateStuff(a,b);
a.DoSomethingWithShared();
b.DoSomethingWithShared();
///...
/// "Shared" instance created in CreateStuff() hopefully lives until here...
}
The idea is that multiple instances of Owner need a shared resource of type Shared.
Is CreateStuff() an error? (ie, does s go out of scope, leaving a and b with invalid pointers to a destroyed object? (Am I returning the address of a temporary in a roundabout way?)
Are there any other scope/GC issues I'm not seeing?
Is there an easier way to do this?
CreateStuff is definitively wrong. You're (eventually) passing a pointer to a local variable into the shared_ptrs, which outlive that variable. Once it goes out of scope, you'll have two dangling pointers inside those _shareds.
Since you're using smart pointers, why not dynamically allocate that Shared on the heap, and let the smart pointers worry about deleting it when they're done?
void CreateStuff(Owner& a, Owner &b)
{
std::shared_ptr<Shared> s(new Shared);
a.Shared(s); // have that Shared() modified to take the shared_ptr,
b.Shared(s); // of course
}
I have a map of addresses that allows me to store arbitrary data with objects. Basically, a library I'm writing has a templated function that winds up storing arbitrary data with objects.
std::map<void *, MyUserData>
This works, until the object passed in is destroyed, leaving its user data in the map. I want the associated user data to be removed as well, so I need to somehow listen for the destructor of the passed in object,
Some example code that illustrates the problem:
#include <map>
#include <memory>
struct MyUserData
{
int someNum;
};
std::map<void *, MyUserData> myMap;
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object)
{
static inc = 0;
myMap[(void *)&_object->get()].someNum = inc++;
}
struct MyObject
{
int asdf;
};
int main(int _argc, char ** _argv)
{
auto obj = std::make_shared<MyObject>();
obj->asdf = 5;
registerObject(obj);
obj = 0;
//The user data is still there. I want it to be removed at this point.
}
My current solution is to set a custom deleter on the shared_ptr. This signals me for when the object's destructor is called, and tells me when to remove the associated user data. Unfortunately, this requires my library to create the shared_ptr, as there is no "set_deleter" function. It must be initialized in the constructor.
mylib::make_shared<T>(); //Annoying!
I could also have the user manually remove their objects:
mylib::unregister<T>(); //Equally annoying!
My goal is to be able to lazily add objects without any prior-registration.
In a grand summary, I want to detect when the object is deleted, and know when to remove its counterpart from the std::map.
Any suggestions?
P.S. Should I even worry about leaving the user data in the map? What are the chances that an object is allocated with the same address as a previously deleted object? (It would end up receiving the same user data as far as my lib is concerned.)
EDIT: I don't think I expressed my problem very well initially. Rewritten.
From you code example, it looks like the external interface is
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object);
I assume there is a get-style API somewhere. Let's call this getRegisteredData. (It could be internal.)
Within the confines of the question, I'd use std::weak_ptr<void> instead of void*, as std::weak_ptr<T> can tell when there are no more "strong references" to the object around, but won't prevent the object from being deleted by maintaining a reference.
std::map<std::weak_ptr<void>, MyUserData> myMap;
template <typename T>
registerObject<T>(const std::shared_ptr<T> & _object)
{
static inc = 0;
Internal_RemoveDeadObjects();
myMap[std::weak_ptr<void>(_object)].someNum = inc++;
}
template <typename T>
MyUserData getRegisteredData(const std::shared_ptr<T> & _object)
{
Internal_RemoveDeadObjects();
return myMap[std::weak_ptr<void>(_object)];
}
void Internal_RemoveDeadObjects()
{
auto iter = myMap.cbegin();
while (iter != myMap.cend())
{
auto& weakPtr = (*iter).first;
const bool needsRemoval = !(weakPtr.expired());
if (needsRemoval)
{
auto itemToRemove = iter;
++iter;
myMap.erase(itemToRemove);
}
else
{
++iter;
}
}
}
Basically, std::weak_ptr and std::shared_ptr collaborate and std::weak_ptr can detect when there are no more std::shared_ptr references to the object in question. Once that is the case, we can remove the ancillary data from myMap. I'm using the two interfaces to myMap, your registerObject and my getRegisteredData as convenient places to call Internal_RemoveDeadObjects to perform the clean up.
Yes, this walks the entirety of myMap every time a new object is registered or the registered data is requested. Modify as you see fit or try a different design.
You ask "Should I even worry about leaving the user data in the map? What are the chances that an object is allocated with the same address as a previously deleted object?" In my experience, decidedly non-zero, so don't do this. :-)
I'd add a deregister method, and make the user deregister their objects. With the interface as given, where you're stripping the type away, I can't see a way to check for the ref-count, and C++ doesn't provide a way to check whether memory has been deleted or not.
I thought about it for a while and this is as far as I got:
#include <memory>
#include <map>
#include <iostream>
#include <cassert>
using namespace std;
struct MyUserData
{
int someNum;
};
map<void *, MyUserData> myMap;
template<class T>
class my_shared_ptr : public shared_ptr<T>
{
public:
my_shared_ptr() { }
my_shared_ptr(const shared_ptr<T>& s) : shared_ptr<T>(s) { }
my_shared_ptr(T* t) : shared_ptr<T>(t) { }
~my_shared_ptr()
{
if (unique())
{
myMap.erase(get());
}
}
};
template <typename T>
void registerObject(const my_shared_ptr<T> & _object)
{
static int inc = 0;
myMap[(void *)_object.get()].someNum = inc++;
}
struct MyObject
{
int asdf;
};
int main()
{
{
my_shared_ptr<MyObject> obj2;
{
my_shared_ptr<MyObject> obj = make_shared<MyObject>();
obj->asdf = 5;
registerObject(obj);
obj2 = obj;
assert(myMap.size() == 1);
}
/* obj is destroyed, but obj2 still points to the data */
assert(myMap.size() == 1);
}
/* obj2 is destroyed, nobody points to the data */
assert(myMap.size() == 0);
}
Note however that it wouldn't work if you wrote obj = nullptr; , or obj.reset(), since the object isn't destroyed in those cases (no destructor called). Also, you can't use auto with this solution.
Also, be careful not to call (void *)&_object.get() like you were doing. If I'm not terribly wrong, by that statement you're actually taking the address of the temporary that _object.get() returns, and casting it to void. That address, however, becomes invalid instantly after.
This sounds like a job for... boost::intrusive (http://www.boost.org/doc/libs/1_53_0/doc/html/intrusive.html)! I don't think the current interface will work exactly as it stands though. I'll try to work out a few more details a little later as I get a chance.
You can just do
map.erase(map.find(obj));
delete obj;
obj = 0;
this will call the destructor for your user data and remove it from the map.
Or you could make your own manager:
class Pointer;
extern std::map<Pointer,UserData> data;
class Pointer
{
private:
void * pointer;
public:
//operator ()
void * operator()()
{
return pointer;
}
//operator =
Pointer& operator= (void * ptr)
{
if(ptr == 0)
{
data.erase(data.find(pointer));
pointer = 0;
}
else
pointer = ptr;
return *this;
}
Pointer(void * ptr)
{
pointer = ptr;
}
Pointer()
{
pointer = 0;
}
~Pointer(){}
};
struct UserData
{
static int whatever;
UserData(){}
};
std::map<Pointer,UserData> data;
int main()
{
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
data[Pointer(new UserData())].whatever++;
Pointer x(new UserData());
data[x].whatever;
x = 0;
return 0;
}
I should get the same in both lines..
what happen I get two different values.. like it was aiming to different positions..
I think the error is inside the d->add(*b)
the output is
thiago 14333804
Ph¿├┌ 2816532
to describe it better I put the code below
I got a program
int main(int argc, char **argv) {
CClass* c = new CClass();
BClass* b = c->getNext();
printf("%s %d \n", b->getValue(), b->getValue());
DClass* d = new DClass();
d->add(*b);
printf("%s %d \n", d->getNext(), d->getNext());
cin.get();
return 0;
}
the interfaces are below
class BClass
{
private:
char* value;
bool stale;
public:
BClass(char* value);
~BClass(void);
char* getValue();
bool isStale();
};
class CClass
{
private:
vector<BClass*> list;
public:
CClass(void);
~CClass(void);
BClass* getNext();
};
class DClass
{
private:
vector<BClass*> list;
static bool isStale(BClass* b) { return b->isStale();};
public:
DClass(void);
~DClass(void);
void add(BClass s);
char* getNext();
};
and the implementation follows
//BClass
BClass::BClass(char* value)
{
this->value = value;
this->stale = false;
}
BClass::~BClass(void)
{
}
char* BClass::getValue()
{
return value;
}
bool BClass::isStale()
{
return stale;
}
//CClass
CClass::CClass(void)
{
list.push_back(new BClass("thiago"));
list.push_back(new BClass("bruno"));
list.push_back(new BClass("carlos"));
}
CClass::~CClass(void)
{
}
BClass* CClass::getNext()
{
return list.at(0);
}
//DClass
DClass::DClass(void)
{
}
DClass::~DClass(void)
{
}
void DClass::add( BClass s )
{
list.push_back(&s);
}
char* DClass::getNext()
{
BClass* b = list.at(0);
return b->getValue();
}
When you pass in an instance of class B into D::add() function you create a deep copy of the object and that copy is what is put on stack. Later on you use the address of that copy to push it into list. Once the function is done this automatic variable goes out of scope thus the pointer you used to put into list is no longer valid.
To fix change your interface to avoid deep copies as follows:
void DClass::add( BClass * s )
{
list.push_back(s);
}
Step-by-step of what your code is doing
BClass* b = c->getNext(); // you get the address of the first element from the list (created in constructor) and assign it to b
d->add(*b); // the *b will dereference the object pointed to by b and put it onto stack in preparation to the call to add()
void DClass::add( BClass s ){ // the deep copy of a dereferenced object is put into this function's stack frame
list.push_back(&s); // an address of that temporary copy of the original object is being used to be added to your list
} // this is where the fun happens - once the function is done it will unwind the stack back up and the memory, previously occupied by that temp copy, will be re-used for other purposes. In your case - it will be used to pass parameters to functions d->getNext() (there's always a hidden this parameter to non-static member functions) and later to the printf() function. Remember - your previous pointer to that temp copy is still pointing to the stack, but it's now occupied by different data, causing you to see corruption
General rule of thumb - never use pointers to temp objects ;-)
in the DClass::add function, BClass s is a local variable.
void DClass::add( BClass s )
{
list.push_back(&s);
}
When you call d->add(*b);, you're passing a BClass by value, meaning you're creating a copy of it, and the address of that copy is not the same address of the original.
s will go out of scope as soon as the function returns, and the pointer to it will be invalid. So storing that pointer is no good to you, since dereferencing it would be undefined behaviour.