I have a class named "Human" and have a vector of humans and I populate it this way:
humans.push_back(Human());
and in another class, I have a vector human* pointing to the previous humans in this way:
cell.humans.push_back(&humans.back())
push_back function creates an object in heap memory and so the object won't change if the stack frames get changed. but apparently, by defining a variable like in a non-related function:
string foo = "a";
one of the humans' attributes are getting overridden and this is an unexpected behavior.
but when I change the code in a way that the first human vector keeps a pointer of human like this:
humans.push_back(new Human())
cell.humans.push_back(humans.back())
the issue will be solved. to debug the program, I even used gdb and set a watchpoint on the changed object but gdb got stock in an infinite loop!!!
how can i explain this behavior?
push_back function creates an object in heap memory and so the object won't change if the stack frames get changed
Yes, but in this case, that object is just a pointer. Its validity depends on the validity of the object it points to. If the reference to humans.back() gets invalidated, then cell.humans' pointers be left dangling. De-referencing them would lead to undefined behaviour.
the reason was interesting. when you push back a new object into a vector, the vector class may change the place and copy the previous objects into a new location(after pushing back a new object) but where are keeping the previous pointers that are now free and are invalidated.
Related
I need a vector of pointers to some preexisting objects, so I would like to create a pointer directly inside the vector.
I thought of calling the emplace_back function of my vector passing new as parameter, but this would not only create the pointer I want, but also an object. To get rid of this undesired collateral effect, I would do a delete pointer, which actually delete the object and leaves the pointer there, and then I would set this pointer to point to the preexisting object that I want. In code, it would be something similar to:
std::vector myVector<ClassType*>;
myVector.emplace_back(new ClassType());
delete myVector.end();
myVector.end()=&preexistingObject;
However, I think it's a waste to create an object just to delete it right after just because I want a pointer!
How can I create a pointer without creating an object in a way that I can create it from inside a parameter list (inside emplace_back in this case)?
I could write
ClassType *myPointer;
But the problem is that I cannot do it from inside emplace_back function as I need.
Any suggestions?
Thanks for your help,
Gustavo
The answer is to pass the address of the pre-existing object to my container as user4581301 suggested.
The only tricky point is that my software started crashing sometimes, and I have it tracked it to be a problem of pointers pointing to gargabe.
This happens because my pre-existing objects are stored inside a vector (std::vector), and when my vector got too big, all my pointers would get invalid, because... The vector changed the memory address of its contents when it has to make room for more items!
The solution is to store the pre-existing objects inside a list (std::list), which guarantess that my pre-existing objects won`t have their address changed when the list get too big.
To resume, in code, what I had to is:
std::list<PreExistingClass> myContainerOfObjects; //This HAS to be a list. Otherwise, dangling pointers!
std::vector<PreExistingClass*> myContainerOfPointerToObjects
myContainerOfObjects.emplace_back();
myContainerOfPointerToObjects.emplace_back(&(myContainerOfObjects.back()));
Thanks!
Gustavo
If, inside a function, I store data in an unordered_set, and then return pointers to the objects being stored, will the pointers still be valid outside of the scope of the function?
eg.
int *myFunc(){
std::unordered_set<int> hashset;
//add some objects
hashset.insert(4);
hashset.insert(5);
hashset.insert(6);
int *intptr = &(*hashset.insert(4)); //try to insert an object that may already be in the set, and get a pointer to the object in the set
return intptr;
}
will trying to access *intptr in another function cause an error? Or is the data in an unordered_set deallocated when the scope of an unordered_set ends?
Yes, in your example you are returning an object which has been destroyed when the destructor of the unordered_set is called, that is when the function exits its scope.
Even though the elements contained in an unordered_set are dynamically allocated (and with elements I mean the objects which contains your effective keys or values) they are also destroyed when the set itself it destroyed.
In practice you could be able to access the data and receive no errors but you shouldn't consider this situation since it's just unsafe. Think only that it is wrong.
To obtain what you need you should take care of inner initialization of objects contained inside the set by yourself. An unique_ptr<int> could do the trick, since returning the value would move it on the destruction of the set and prevent the object from being deallocated.
The short answer is yes.
The memory inside the hashset object should be considered invalid after the function is called. Thus returning a pointer to the internals of that object will have undefined behavior.
The longer answer is maybe.
However, the state of that memory may remain unchanged for some time after the function has returned. Thus you may get "correct" results from the code despite the memory being invalid.
The longest answer is it depends.
How the memory is handled will depend greatly on the platform that you are running on. Memory constrained systems may perform memory management very differently from desktops.
I just waste hours on a simple line causing data loss. I have AnotherClass holding a vector of instances of MyClass. This AnotherClass instantiates objects of MyClass the following way:
AnotherClass::AnotherClass(){
MyClass myObject(...);
myVector.push_back(&myObject);
}
The address of myObject is afterwards pushed into a vector (with other instances of MyClass), like written in the code. When I start using instances of AnotherClass I notice the values of MyClass were lost (completely random). When I change the code to:
AnotherClass::AnotherClass(){
MyClass* myObject = new MyClass(...);
myVector.push_back(myObject);
}
I don't have data loss.
Can somebody be so kind to explain me why the second way of creating objects doesn't lead to a loss of data? (without referencing me to books of 1.000 pages)
Simple. The first version creates a local variable on the stack, which gets destroyed automatically when it goes out of scope (at the end of the function)
Your vector just contains a pointer to where the object used to be.
The second version creates an object on the heap, which will live until you eventually delete it.
The reason is RAII.
In the first snippet you declare an object in the scope of your method/constructor.
As soon this scope ends, this is the case when method is finished, your object gets out-of-scope and becomes cleaned for you (this means that its desctructor is called). Your vector now still holds pointers to your already cleaned and thus invalid objects, thats the reason why you get garbage.
In the second snippter, your object are contained on the heap. They wont become cleaned / destroyed unless you call delete myObj;. Thats the reason why they remain valid even after the method has finsihed.
You can solve this on multiple ways:
Declare your vector as std::vector<MyClass> (notice, not a pointer type)
Keep your second snippet but make sure to delete all elements of your vector once your done
Use smart pointers if you dont want to cleanup your objects by your own (e.g std::shared_ptr or std::unique_ptr)
The first way allocates a MyClass object on the stack. That object will be deallocated the moment it goes out ofscope, I.e. when the constructor has run its course.
The second way allocates the object in dynamic memory. That object will continue to exist until you call delete on it.
The second way is the way to do it but you should add a destructor to AnotherClass that iterates through the vector and deletes all objects. Otherwise your program will have a memory leak.
I am coming from a C# background to C++. Say I have a method that creates a object in a method on the stack, then I pass it to another classes method which adds it to a memeber vector.
void DoStuff()
{
SimpleObj so = SimpleObj("Data", 4);
memobj.Add(so);
}
//In memobj
void Add(SimpleObj& so)
{
memVec.push_back(so); //boost::ptr_vector object
}
Here are my questions:
Once the DoStuff methods ends will the so go out of scope and be popped from the stack?
memVec has a pointer to so but it got popped what happens here?
Whats the correct way to pass stack objects to methods that will store them as pointers?
I realise these are probably obvious to a C++ programmer with some expereince.
Mark
Yes.
The pointer remains "alive", but points to a no-longer-existent object. This means that the first time you try to dereference such pointer you'll go in undefined behavior (likely your program will crash, or, worse, will continue to run giving "strange" results).
You simply don't do that if you want to keep them after the function returned. That's why heap allocation and containers which store copies of objects are used.
The simplest way to achieve what you are trying to do would be to store a copy of the objects in a normal STL container (e.g. std::vector). If such objects are heavyweight and costly to copy around, you may want to allocate them on the heap store them in a container of adequate smart pointers, e.g. boost::shared_ptr (see the example in #Space_C0wb0y's answer).
Another possibility is to use the boost::ptr_vector in association with boost::ptr_vector_owner; this last class takes care of "owning" the objects stored in the associated ptr_vector, and deleting all the pointers when it goes out of scope. For more information on ptr_vector and ptr_vector_owner, you may want to have a look at this article.
To achieve your goal, you should use a shared_ptr:
void DoStuff()
{
boost::shared_ptr<SimpleObj> so(new SimpleObj("Data", 4));
memobj.Add(so);
}
//In memobj
void Add(boost::shared_ptr<SimpleObj> so)
{
memVec.push_back(so); // std::vector<boost::shared_ptr<SimpleObj> > memVec;
}
Yes your so object will be popped off the stack once your function leaves scope. You should create a heap object using new and add a pointer to that in your vector.
As said before, the pointer in your vector will point to something undefined once your first function goes out of scope
That code won't compile because inside the Add function you're trying to trying to push a whole object into a vector that expects a pointer to an object.
If instead you were to take the address of that object and push that onto the vector, then it would be dangerous as the original object would soon be popped off the stack and the pointer you stored would be pointing to uninitialised memory.
If you were using a normal vector instead of a pointer vector then the push_back call would be copying the whole object rather than the pointer and thus it would be safe. However, this is not necessarily efficient, and the 'copy everything' approach is probably not intuitive to someone from the C#, Java, or Python worlds.
In order to store a pointer to an object it must be created with new. Otherwise it will disappear when going out of scope.
The easiest solution to your problem as presented here would be to use std::vector instead of boost::ptr_vector, because this way the push_back would copy the object in the vector
What I am trying to do is essentially create two vectors of objects, where some objects are entered into both lists and some are just entered into one. The first problem I found was that when I used push_back() to add an object into both lists the object was copied so that when I changed it from one list the object did not change in the other. To get around this I tried to create a list of pointers to objects as one of the lists. However when I accessed the pointer later on the data seemed to be corrupted, the data member values were all wrong. Here are some snippets of my code:
Definition of vectors:
vector<AbsorbMesh> meshList;
vector<AbsorbMesh*> absorbList;
...
Adding an object to both:
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
// Add to the absorption list
absorbList.push_back(&nurbsMesh);
// Store the mesh in the scene list
meshList.push_back(nurbsMesh);
Accessing the object:
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0]->receivedPower;
}
What am I doing wrong?
There's some details missing, but at a guess.
nurbsMesh goes out of scope between the push_back and the absorbList[0]->receivedPower.
So now your vector of pointers contains a pointer to an object that doesn't exist anymore.
Try adding a copy constructor to your AbsorbMesh class and adding to your vector like this.
absorbList.push_back(new AbsorbMesh(nurbsMesh));
meshList.push_back(nurbsMesh);
don't forget to delete the objects in absorbList, like this
for(vector<AbsorbMesh*>::iterator it = absorbList.begin(); it != absorbList.end(); it++) {
delete it;
}
Or store a shared pointer in your vector instead of a bare pointer. Boost has a good shared pointer implementation if you're interested. See the docs here
If you want to have updates to items in one vector modify objects in the other vector, then you'll need to store pointers in both vectors.
Using your original requirements (updating an item in one vector affects items in the other vector, here's how I'd do it with a boost shared pointer. (WARNING, untested code)
vector<boost::shared_ptr<AbsorbMesh> > meshList;
vector<boost::shared_ptr<AbsorbMesh> > absorbList;
boost::shared_ptr<AbsorbMesh> nurb = new AbsorbMesh(nurbs.CreateMesh(uStride, vStride));
meshList.push_back(nurb);
absorbList.push_back(nurb);
...
...
if (absorbList.size() > 0)
{
float receivedPower = absorbList[0].get()->receivedPower;
}
You are storing the address of an object allocated on stack. The nurbsMesh object gets destroyed as soon as your method which does push_back() ends. If you try to access this pointer afterwards the object is already destroyed and contains garbage. What you need is to retain the object which remains even after the function goes out of scope. To do this allocate the memory for the object from heap using new. But for every new you should have a corresponding delete. But in your case you'll have problems deleting it as you are pushing the same pointer into two vectors. To solve this, you would require some type reference counting mechanism.
Object is deleted when you try get pointer from vector.
Try do
vector.push_back(new Object);
Once you have fixed the problem that others mentioned (storing a pointer to an object that's on the stack), you're going to run into another issue. A vector may reallocate, which results in its contents moving to another location.
The safe way to do this, then, is to store pointers in both vectors. Then, of course, you need to ensure that they get deleted... but that's C++ for you.
absorbList.push_back(&nurbsMesh); is wrong
absorbList save pointer to local object. When nurbMesh is destroyed you can not write
absorbList[0]->
However when I accessed the pointer later on the data seemed to be corrupted
When you put something on a vector, the vector might move it from one physical location to another (especially e.g. when the vector is resized), which invalidates any pointer to that object.
To fix that, you'll need to store a pointer (possibly a 'smart pointer') in both vectors (instead of having one vector contain the object by value).
If you're going to do this, it might be a good idea to disable the object's copy constructor and assignment operator (by declaring them as private, and not defining them) to ensure that after an object is created it cannot be moved.
There are several things wrong with your example
AbsorbMesh nurbsMesh = nurbs.CreateMesh(uStride, vStride);
This object is allocated on the stack. It is a purely local object. This object is going to be destroyed when you reach the end of the current block surrounded by {}.
absorbList.push_back(&nurbsMesh);
Now you get the pointer to the object that most likely will be destroyed.
meshList.push_back(nurbsMesh)
And this copies an entirely new object on the vector.
It is equally wrong to push the object on the vector first and then push a pointer to the object on the vector using absorbList.push_back( &meshList.back() ) because vector::push_back will reallocate the whole vector, invalidating all pointers.
You might be able to create all AbsorbMesh objects first, push them onto a vector, and then get the pointers to these objects in the vector. As long as you don't touch the vector, you'll be fine.
Alternatively, create objects on the heap using new AbsorbMesh() but make sure to call delete on each pointer thus created. Otherwise you have a memory leak.
Third solution, avoid the trouble and use smart pointers that take care of object destruction for you.
First, as everybody else points out, you can't allocate objects on the stack (i.e., other than by new or something similar), and have them around after leaving the scope.
Second, having objects in an STL container and maintaining pointers to them is tricky, since containers can move things around. It's usually a bad idea.
Third, auto_ptr<> simply doesn't work in STL containers, since auto_ptrs can't be copied.
Pointers to independently allocated objects work, but deleting them at the right time is tricky.
What will probably work best is shared_ptr<>. Make each vector a vector<shared_ptr<AbsorbMesh> >, allocate through new, and at a slight cost in performance you avoid a whole lot of hassle.