I want to make a vector of objects, but I don't want to allocate them on the heap. I want to allocate them onto stack memory. But I'm running into issues.
struct Object { int x; Object(int x) { this->x = x; } };
int main() {
std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
Object o (i);
v.push_back(&o);
std::cout << &o << std::endl; // keeps printing the same mem address...
// ...implying that these are all the same object
}
}
I have a suspicion that the object is deleting itself after going out of scope after each iteration of the for-loop.
Now, I know that you can just do v.push_back(new Object(i)) for each iteration and it would work. However, I do not want these objects allocated onto the heap where I need to manually manage the memory.
You are basically correct that "object is [being destructed] after going out of scope". It's also confusing because of what you're printing. Based on how the compiler allocates the variables with "automatic storage duration" within the loop, the stack variable Object o always has the same address.
std::vector<Object*> v;
for (int i = 0; i < 5; i++) {
Object o (i);
v.push_back(&o);
// Variable o still exists on the stack
std::cout << &o << std::endl; // Prints the address of the automatic variable 'o'
}
// At this point, no objects exist; they all went out of scope
// every pointer in v is invalid, pointing to the "ghost" of a destoryed object.
I think the simpler approach you are looking for is to simply create a vector of objects.
std::vector<Object> v;
for (int i = 0; i < 5; i++) {
v.push_back(Object(i));
std::cout << &(v.back()) << std::endl; // Prints the address of the Object just added
}
That said, you should understand that the std::vector<Object> will manage your object lifetimes properly, destroying the objects when the vector itself goes out of scope. But the objects are actually stored on the free store. This is okay.
Here is the output from ideone when compiling and running with a vector of Objects:
0x8e66008
0x8e6601c
0x8e66030
0x8e66034
0x8e66050
If you really don't want to allocate them on the stack, but instead just want the memory managed, you really should take few hours to fill in some knowledge gaps.
In particular, picking up a good amount of knowledge on RAII is crucial to using C++ and C++11 effectively. I highly recommend The C++ Language Reference, 4th Edition. The 4th edition is important because it's very different from the the 3rd edition.
In it, it'll show you that will likely want to use std::vector<std::unique_ptr> for this particular problem, or to make Object a managed object itself (with move semantics implemented).
The vector is deleted, not the objects.
The following means that you save pointers in the vector v:
std::vector<Object*> v;
You could do this:
std::vector<Object> v;
in which case you get many objects, but then you get copies of your objects which at times is either not possible or not something you want (although newer version of the C++ compiler can do a move instead of a copy, but I don't think that would work in this case...)
Another way if you want the Objects to be allocated and then automatically deleted is to use a smart pointer.
#include <memory>
std::vector<std::shared_ptr<Object> > v;
In that case the Objects are allocated by you and freed whenever the vector gets deleted.
However, your problem is that you initialize objects on the stack and assign that stack pointer to your vector. I would image that your print shows you that the pointer is always the same... meaning that the previous object gets destroyed and a new one created on each iteration.
So I would replace these lines:
std::vector<Object*> v;
Object o (i);
v.push_back(&o);
By something like this:
std::vector<std::shared_ptr<Object> > v;
std::shared<Object> o(new Object(i));
v.push_back(o);
If you do not know anything about shared pointers, I suggest you read up on them. It's very useful whenever you allocate objects with new. Also there are a few traps with what is called circular references (i.e. check out weak_ptr as well). But in this way you do not have to manage memory and you have good pointers.
If you prefer the solution with the Object by itself, it would be something like this:
std::vector<Object> v;
Object o(i);
v.push_back(o);
This way you avoid the heap, however, you make copies each time you push_back (or a move). So if your objects are big, that's not a good idea.
Also, within your object, if you end up having pointers, using smart pointers will help you greatly too. So that's anyway a good idea to learn about them.
Related
I was thinking about a this situation not for a real implementation but to understand better how pointers works.
class foo(){
foo();
~foo();
void doComplexThings(const std::vector<int*>& v){
int* copy;
for(int i = 0; i < v.size(); i++){
copy = v[i];
// do some stuffs
}
}
}
main(){
std::vector<int*> myVector; // suppose we have 100 elements
doComplexThings(myVector);
for(int i = 0; i < myVector.size(); i++){
delete myVector[i];
}
myVector.clear();
}
Ok, I know that have no sense to copy v[i] inside an other pointer, but I was thinking: copy do a memory leak?
After the execution of doComplexThings(), copy will continue to exist and will occupy space in the heap?
After deleting all elements it will continue to exist and point to a deallocated memory?
So logically if I do this things with complex objects I'll keep occupy the memory with unreference object? Or copy is saved in the stack because I don't use new? And at the end of doComplexThings it will be deleted?
I'm a bit confused, thanks!
There is some confusion on the topic of pointers in the C++ community. While it is true that smart pointers have been added to the library to alleviate problems with dynamic memory allocation, raw pointers are not obsolete. In fact, whenever you want to inspect another object without owning it, you should use a reference or raw pointer, depending on which suits your needs. If the concept of ownership is unclear to you, think of an object as being owned by another object if the latter is responsible for cleaning up afterwards (deleting the former).
For example most uses of new and delete should be replaces with the following (omitting std for brevity):
{
auto ptr_to_T = make_unique<T>(//constructor params);
do_stuff_with_smart_ptr(ptr_to_T);
do_stuff_with_T(*ptr_to_T);
do_stuff_with_raw_ptr(ptr_to_T.get());
} // automatic release of memory allocated with make_unique()
Notice how a function that takes a T* doesn't need a smart pointer if it doesn't keep a copy of the T* it is given, because it doesn't affect the lifetime of the object. The object is guaranteed to be alive past the return point of do_stuff_with_T() and its function signature signals that it doesn't own the object by taking a raw pointer.
On the other hand, if you need to pass the pointer to an object that is allowed to keep the pointer and reference it later, it is unclear when the object will need to be destroyed and most importantly by whom. This is solved via a shared pointer.
ClassThatNeedsSharedOwnership shared_owner;
{
auto ptr_to_T = make_shared<T>(//constructor params);
shared_owner.set_T(ptr_to_T);
// do a lot of stuff
}
// At this point ptr_to_T is destroyed, but shared_owner might keep the object alive
So how does the above factor in to your code. First of all, if the vector is supposed to own (keep alive) the ints it points to, it needs to hold unique_ptr<int> or shared_ptr<int>. If it is just pointing to ints held by something else, and they are guaranteed to be alive until after the vector is destroyed, you are fine with int*. In this case, it should be evident that a delete is never necessary, because by definition your vector and the function working on the vector are not responsible for cleaning-up!
Finally, you can make your code more readable by changing the loop to this (C++11 which you've tagged in the post):
for (auto copy : v){
// equivalent to your i-indexed loop with copy = v[i];
// as long as you don't need the value of i
do_stuff_to_int_ptr(copy);
// no delete, we don't own the pointee
}
Again this is only true if some other object holds the ints and releases them, or they are on the stack but guaranteed to be alive for the whole lifetime of vector<int*> that points to them.
No additional memory is allocated on the heap when you do this:
copy = v[i];
variable copy points to the same address as v[i], but no additional array is allocated, so there would be no memory leak.
A better way of dealing with the situation is to avoid raw pointers in favor of C++ smart pointers or containers:
std::vector<std::vector<int>> myVector;
Now you can remove the deletion loop, which is an incorrect way of doing it for arrays allocated with new int[length] - it should use delete[] instead:
delete[] myVector[i];
Basically you're illustrating the problem with C pointers which lead to the introduction of C++ unique and shared pointers. If you pass a vector of allocated pointers to an opaque member function, you've no way of knowing whether that function hangs onto them or not, so you don't know whether to delete the pointer. In fact in your example you don't seem to, "copy" goes out of scope.
The real answer is that you should only seldom use allocated pointers in C++ at all. The stl vector will serve as a safer, easier to use version of malloc / new. Then you should pass them about as const & to prevent functions from changing them. If you do need an allocated pointer, make one unique_ptr() and then you know that the unique_ptr() is the "owner" of the memory.
class Example
{
public: int i;
Example(const Example &e)
{
i = e.i;
}
Example(int i)
{
this->i = i;
}
};
int main()
{
std::vector<Example*> vec;
std::vector<Example*> newVec;
Example* ex1 = new Example(1);
Example* ex2 = new Example(2);
vec.push_back(ex1);
vec.push_back(ex2);
//newVec = vec; --> This does shallow copy
for(int i=0; i<vec.size(); ++i) // --> Deep copy
{
Example newE(*(vec[i]));
newVec.push_back(&newE);
}
for(int i=0; i<newVec.size(); ++i)
{
std::cout << "\nfoobar" << newVec[i]->i << "\n";
}
}
The above code prints foobar2 twice. Shouldn't it print foobar1 and foobar2? Also, is this the best way to copy a vector containing objects? I want deep copying.
for(int i=0; i<vec.size(); ++i) // --> Deep copy
{
Example newE(*(vec[i]));
newVec.push_back(&newE);
}
In this code you make a copy of vec[i] to Example newE. Then you push_back the address of newE to the newVec vector. Then the newE object goes out of scope and is destroyed, so you end up having a pointer to garbage inside newVec.
If you want a deep copy of vector content, and you want to store owning pointers to objects, consider using vector of smart pointers, e.g. vector<shared_ptr<Example>>.
In this case, you can simply copy the vectors with operator=, and the reference counts of the shared_ptrs will be automatically updated.
Yoy may want to consider also the simpler design of just having vector<Example> (without pointer indirection).
Your code is not correct and results in undefined behavior.
This loop is problematic:
for(int i=0; i<vec.size(); ++i) // --> Deep copy
{
Example newE(*(vec[i]));
newVec.push_back(&newE);
}
You declare a local variable newE. Such variable has automatic storage duration (often referred as stack allocated, although the C++ standard technically does not require a stack to be used to implement them).
Variables with automatic storage duration have the following properties:
Their lifetime start at the point they are declared.
Their lifetime end at the end of the scope they are declared in.
Each iteration of your for loop is a scope, so after the first iteration, newE is not valid anymore and the compiler is free to generate instructions that will reuse the memory.
This is exactly what happen in your case (and in any decent implementation): each iteration will place newE at the exact same address.
But, as you used operator& to take the address of newE, and newE then goes out of scope, you now have a dangling pointer.
Dangling pointers by themselves are not problematic, but you can't do anything really meaningful with them. In particular, dereferencing one results in undefined behavior.
You have multiple ways to fix your code.
The easy way would be using new:
Example* newE = new Example(*vec[i]);
newVec.push_back(newE);
But you would then have to make sure to add the appropriates delete too. Also, this is not really pedantic C++.
Another way would be to change vec and newVec to std::vector<Example>, to sidestep the raw pointers issues. This would be the preferred way to express your code in C++.
In some cases you need the pointers, if you do polymorphism for example. Then, you may use std::unique_ptr or std::shared_ptr to have pointer semantics and RAII.
Example newE(*(vec[i]));
newVec.push_back(&newE);
allocates newE on the stack, then pushes a pointer to it into the vector. newE goes out of scope at the end of the loop iteration, and you just go lucky that the location of newE is not reused. It seems the compiler generated code that puts both stack-instances in the same place, so you overwrite that location with the second value, then you de-reference that location twice, when iterating over the vector of pointers.
I know that variables allocated on that stack of a function become inaccessible when the function finishes execution. However, vector types allocate their elements on the heap no matter how they are allocated. So for instance,
vector<int> A;
will allocate space for its elements on the heap instead of the stack.
My question is, assume I have the following code:
int main(int argc, char *argv[]) {
// initialize a vector
vector<int> A = initVector(100000);
// do something with the vector...
return 0;
}
// initialize the vector
vector<int> initVector(int size) {
vector<int> A (size); // initialize the vector "on the stack"
// fill the vector with a sequence of numbers...
int counter = 0;
for (vector<int>::iterator i = A.begin(); i != A.end(); i++) {
(*i) = counter++;
}
return A;
}
Will I have memory access problems when using the vector A in the main function? I tried this several times and they all worked normally, but I'm scared that this might just be luck.
The way I see it is, the vector A allocates its elements on the heap, but it has some "overhead" parameters (maybe the size of the vector) allocated on the stack itself. Therefore, using the vector in the main function might result in a memory access problem if these parameters are overwritten by another allocation. Any ideas?
When you do "return A;" you return by value, so you get a copy of the vector -- C++ creates a new instance and calls copy constructor or operator= on it. So in this case it doesn't matter where the memory was allocated as you have to copy it anyway and destroy the old copy (some possible optimizations notwithstanding).
The data in the vector (and all other STL containers) is moved around by value as well, so you store the copy of your integers, not pointers to them. That means your objects can be copied around several times in any container operation and they must implement a copy constructor and/or assignment operator correctly. C++ generates those for you by default (just calling copy ctor on all your member variables), but they don't always do the right thing.
If you want to store pointers in an STL container consider using shared pointer wrappers (std::shared_ptr or boost::shared_ptr). They will ensure the memory is handled correctly.
Yes, it will work normally because the memory for the elements are allocated and that is what will be used to build the vector<int> A = variable. However, performance wise, it is not the best idea.
I would suggest changing your function to be the following though
void initVector(vector<int>& a, int size)
For additional references on usage, please see Returning a STL vector from a function… and [C++] Returning Vector from Function.
For an additional reference on performance (using C++11), please see Proper way (move semantics) to return a std::vector from function calling in C++0x
C++ vector actually has two pieces of memory that are linked with a single pointer. The first one is in stack, and the 2nd one in heap. So you have features of both stack and heap in a single object.
std::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
std::cout << sizeof(vec) << std::endl;
Once you run that code, you'll notice that the stack area does not contain the elements, but it still exists. So when you pass the vector from function to another, you'll need to manipulate the stack areas, and the vector will get copied like any other stack-based object.
I want to store 10 Obj object in objList, but i don't know when is appropriate use delete in this case. If i use delete Obj; in the line where i note in below code, will the Obj still be stored in objList?
struct Obj {
int u;
int v;
};
vector<Obj> objList;
int main() {
for(int i = 0; i < 10; i++) {
Obj *obj = new Obj();
obj->u = i;
obj->v = i + 1;
objList.push_back(*obj);
// Should i use "delete Obj;" here?
}
}
Any object you create on the heap with new needs to be cleared up by delete. In your code, you are actually storing a copy in your collection.
objList.push_back(*Obj);
What this line is doing step by step is:
Indirecting a pointer to the underlying heap memory Obj occupies (returning the object Obj)
Calling the copy constructor to create a temporary copy
Storing the temporary copy in the collection
You do not need to create this initial Obj on the heap, a stack allocated local will suffice as #Luchian Grigore has pointed out.
Obj obj;
objList.push_back(obj);
You do not need to call delete on the copy in the collection, the STL collection will handle this memory itself when you remove the element, but you still will need to delete the original heap allocated object.
It would be better if you stored your objects by std::shared_ptr. That way delete would be called when all references to the Obj were removed.
std::vector< std::shared_ptr< Obj > > vec;
vec.push_back( std::make_shared( new Obj() ) );
Yes, you should.
There should be a corresponding delete for every new in your program.
But your program doesn't need dynamic allocation:
Obj obj;
obj.u = i;
obj.v = i + 1;
objList.push_back(obj);
Also, your syntax was wrong - objList.push_back(*Obj); // should be *obj, not *Obj
Think about what happens:
In your loop you create a new instance of Obj and assign some values to it. This instance is created on your heap - thus you have to free it afterwards. When you add the instance to the vector you implicitely create a copy of it - because you have a vector of objects, not of pointers. Thus the vector keeps its own copy of Obj. You are safe to delete your Obj instance.
BTW:
you could even reuse the object instance and create and free it outside of your loop
it's not necessary to allocate the Obj instance on the heap
Obj x; x.u =i; x.v = i+1; objList.push_back(x);
would also do
You should read some articles about smart pointers and smart pointer containers. Eg. boost::scoped_ptr, boost::shared_ptr, std::auto_ptr. Using these paradigms there's usually no need to call delete by yourself.
You wanna use the heap, so I suggest changing your vector declaration to vector of pointers, something like this.
vector<Obj *>objList;
Why? Because if it is a vector of Obj's, then the things you're storing are actually copies of the value Obj of the pointers you created. objList's items and the obj pointers you create are totally separated and unrelated!
So when you,
delete obj
The things on objList are totally completely unaffected in any ways.
Moreover, vector<Obj> (no asterisk), stores its item as Obj and they are on the stack, they will disappear when your program goes out of scope!
Well, the simple rule is that each variable constructed by new should be clean up by delete.
However depending on your goal, you may not need write the delete yourself.
At home, when learning the gory details of memory management, you will probably write as many delete as you write new.
Professionals, however, never use delete in applicative code (*). delete is a code smell. It's the shortest way to memory leaks in the presence of exceptions. Professionals use RAII to deal with exceptions safely, and namely: smart pointers/smart containers.
(*) as opposed to library code, ie someone wrote that shared_ptr class one day.
Using C++:
I currently have a method in which if an event occurs an object is created, and a pointer to that object is stored in a vector of pointers to objects of that class. However, since objects are destroyed once the local scope ends, does this mean that the pointer I stored to the object in the vector is now null or undefined? If so, are there any general ways to get around this - I'm assuming the best way would be to allocate on the heap.
I ask this because when I try to access the vector and do operations on the contents I am getting odd behavior, and I'm not sure if this could be the cause or if it's something totally unrelated.
It depends on how you allocate the object. If you allocate the object as an auto variable, (i.e. on the stack), then any pointer to that object will become invalid once the object goes out of scope, and so dereferencing the pointer will lead to undefined behavior.
For example:
Object* pointer;
{
Object myobject;
pointer = &myobject;
}
pointer->doSomething(); // <--- INVALID! myobject is now out of scope
If, however, you allocate the object on the Heap, using the new operator, then the object will remain valid even after you exit the local scope. However, remember that there is no automatic garbage collection in C++, and so you must remember to delete the object or you will have a memory leak.
So if I understand correctly you have described the following scenario:
class MyClass
{
public:
int a;
SomeOtherClass b;
};
void Test()
{
std::vector<MyClass*> v;
for (int i=0; i < 10; ++i)
{
MyClass b;
v.push_back(&b);
}
// now v holds 10 items pointers to strange and scary places.
}
This is definitely bad.
There are two primary alternatives:
allocate the objects on the heap using new.
make the vector hold instances of MyClass (i.e. std::vector<MyClass>)
I generally prefer the second option when possible. This is because I don't have to worry about manually deallocating memory, the vector does it for me. It is also often more efficient. The only problem, is that I would have to be sure to create a copy constructor for MyClass. That means a constructor of the form MyClass(const MyClass& other) { ... }.
If you store a pointer to an object, and that object is destroyed (e.g. goes out of scope), that pointer will not be null, but if you try to use it you will get undefined behavior. So if one of the pointers in your vector points to a stack-allocated object, and that object goes out of scope, that pointer will become impossible to use safely. In particular, there's no way to tell whether a pointer points to a valid object or not; you just have to write your program in such a way that pointers never ever ever point to destroyed objects.
To get around this, you can use new to allocate space for your object on the heap. Then it won't be destroyed until you delete it. However, this takes a little care to get right as you have to make sure that your object isn't destroyed too early (leaving another 'dangling pointer' problem like the one you have now) or too late (creating a memory leak).
To get around that, the common approach in C++ is to use what's called (with varying degrees of accuracy) a smart pointer. If you're new to C++ you probably shouldn't worry about these yet, but if you're feeling ambitious (or frustrated with memory corruption bugs), check out shared_ptr from the Boost library.
If you have a local variable, such as an int counter, then it will be out of scope when you exit the function, but, unless you have a C++ with a garbage collector, then your pointer will be in scope, as you have some global vector that points to your object, as long as you did a new for the pointer.
I haven't seen a situation where I have done new and my memory was freed without me doing anything.
To check (in no particular order):
Did you hit an exception during construction of member objects whose pointers you store?
Do you have a null-pointer in the container that you dereference?
Are you using the vector object after it goes out of scope? (Looks unlikely, but I still have to ask.)
Are you cleaning up properly?
Here's a sample to help you along:
void SomeClass::Erase(std::vector<YourType*> &a)
{
for( size_t i = 0; i < a.size(); i++ ) delete a[i];
a.clear();
}