Lets say I have a object whose purpose is to hold a bunch of pointers for an object type MyObject, and lets say I want a function that adds new MyObjects to the collection like so:
void MyCollection::addObject(){
MyObject *newObject = new MyObject();
MyCollection.add(mycollection, newObject);
}
Lets say that MyCollection.add takes in a particular collection object and a pointer and somehow internally stores it. However the problem with this function is while the newObject itself is persistent, the *newObject pointer gets destroyed after the function call so the add() function no longer has a pointer that really points to the object. Is there any good way to make a persistent pointer somehow?
Thanks
However the problem with this function is while the newObject itself
is persistent, the *newObject pointer gets destroyed after the
function call so the add() function no longer has a pointer that
really points to the object.
This betrays a huge misunderstanding about how objects and pointers work.
A pointer is an address. new creates an object on the heap and returns the address. When you pass that address to the collection the collection gets a copy of the address, which is exactly the same as the address you got from new. When the variable newObject goes out of scope and is destroyed, the collection still has the copy of the address, and the address still points to the object. No matter how many copies of the address you make and destroy, the address is still good and the object that the address points to is still good.
In fact, the address you get back from new is a copy of the address that new generated internally, and that original, internal value is destroyed. And when you say MyObject *newObject = new MyObject(); you're making another copy. But it doesn't matter because every copy of the address is as good as every other one.
Stack-based data -- like your pointer -- doesn't get "destroyed", per se. The variable itself goes out of scope, but the data it contained -- i.e., the address of the MyObject object -- is still totally valid. If the add() method copies the value of the pointer, all will be good.
Incidentally, I hope that the implementation of add() is just
myVector.push_back(newObject);
where myVector is an instance of std::vector. No need to reinvent the wheel!
The code as written is fine. The pointer will be (must be) copied by the add() method, whose signature is presumably void add(MyObject*).
By the way, your C++ here is invalid:
MyCollection.add(mycollection, newObject);
It should probably be:
mycollection.add(newObject);
This is not a problem. A well defined add function will make a copy of the pointer, so the original pointer going out of scope won't cause any issues.
Related
This is an educational question:
If I have created a class
class bank_account
And in the main function, I declared
bank_account *pointer = new bank_account();
Then I am initializing variables such as follows
(*pointer).account_name ="Random Name";
My confusion is what is happening here because I usually declare an object with a NAME, not a pointer, if that object is a pointer, and a pointer is just some variable which holds an address to a variable. What does it mean if a pointer is declared as an object and what it is actually representing? Is the pointer to an object is referring to an invisible object?
and a pointer is just some variable which holds an address to a variable
Correction: A pointer can point at any object; Not necessarily a variable. Variables have names. There can be objects that are not directly named by a variable such as sub-objects, temporaries, and objects in dynamic storage.
In your program for example, the expression new bank_account() creates an object in dynamic storage.
What does it mean if a pointer is declared as an object
It's really unclear what you mean by "declared as an object". If you declare a pointer to have the type bank_account*, it means that it can point at an object of type bank_account, which happens to be a class.
If you declare a variable to have a pointer type, then the object named by the variable is a pointer.
and what it is actually representing?
A pointer represents the address of an object. Besides containing an address of an object, it can also have the null pointer value (which points to no object) or it can have an invalid value (an address that may have contained an object, but that object no longer exists).
Then I am initializing variables such as follows
(*pointer).account_name ="Random Name";
To be pedantic, this technically does not initialise a variable. Initialisation is performed on objects when they are created. This member variable has been created earlier and this expression assigns a value to it. But if the variable is previously uninitialised, then colloquially speaking, it would not be terribly wrong to talk about initialisation.
when I declare an object as pointer what is the pointer pointing to?
In your example program, pointer points to an object that was created in dynamic storage, using the keyword new.
In general, pointer points at some object whose address is stored in the pointer, or a pointer might not point at an object at all (invalid, or null value).
You said an object is created
Yes. The new-expression creates an object in dynamic storage.
but I declared a pointer
Yes. You did.
so the pointer is pointing to the object?
You've initialised the value of the pointer with the result of the new-expression. The pointer points at the object that was created in dynamic storage.
and what is the name of that object then?
Objects do not have names. However: Variables do have names, and variables are associated with an object, so one could colloquially say that those objects associated with a variable have a name. But objects in dynamic storage are not named by a variable.
a pointer is a variable which contains an address of another variable. Any pointer uses space in memory needed to keep the address. on 64-bit platforms it usually needs 8 bytes.
When you create an class object, it also is resided in memory and occupies as many bytes as it needs. The pointer gets assigned a value of the address of this class object.
bank_account *pointer = new bank_account();
The above declares a pointer to the object of type bank_account. new allocates space for the object in the memory and returns its address. It also calls a constructor of the class. The address returned by the new gets assigned to the pointer variable named pointer. Later you can use it to access the object as
(*pointer).account_name ="Random Name";
or equivalently
pointer->account_name ="Random Name";
pointer is just an address. Pointer type is just a syntactic sugar which allows the compiler to do its job and to provide you with useful information about your program.
A pointer is a variable that holds a memory address, and it exists wherever it is pointing to something that makes sense or not, meaning you can declare this pointer and not necessarily instance an object for it to point to, it can just point to nullptr which generally signifies the object does not exist at that moment. This alone is useful. You can use it as place holder or to keep track of the program's state.
Another property is that it can point to an array of objects, so you may use it to create a dynamic number of objects at once instead of just one or a predetermined number of objects.
But the most important property is that the object you instance with new does not belong to that particular scope, if the function ends it will not be automatically deleted. This object can be created in a subroutine and then exist throughout the program's life or until you delete it, and all you have to do to pass this object around is pass it's pointer, which is a quite small piece of data compared to doing something silly like copying the object around, this is huge for performance.
You have to pay attention to memory leaks though. Since this object is not deleted automatically, you have to do it yourself when necessary, otherwise the longer the program runs, more memory it will use until it runs out of it.
You can also have multiple pointers pointing to the same place, which is very useful when iterating through linked lists, arrays and all sorts of structures, so a pointer's purpose doesn't necessarily have to be that of holding a specific object, but that of a tool to browse data in memory efficiently.
I'm sorry if this question as already been asked but I have no idea how to word this right.
So I'm building an application which needs to be really memory efficient since its on an Arduino Uno (2kbyte sram) and cant load a full array of class objects I need, so I decided to load it in parts.
This is basically how I plan to do it:
//declare class object array
MyClass objects[10];
objects[0] = MyClass(*parameters for initializing*);
....
....
//Some code with objects
//now changing the objects
objects[0] = MyClass(*parameters for initializing*);
Now my question is will the first objects[0] memory be freed when I change object[0] to the other value?
As far as I understand an object is basically a pointer to the fields of the class and when calling a constructor you get a new pointer to a object, so what I'm doing in the code is changing what objects[0] is pointing at but I'm not sure the first pointed at value of objects[0] memory gets freed.
As far as I understand an object is basically a pointer to the fields of the class and when calling a constructor you get a new pointer to a object[.]
No, in C++ an object is... well, an actual object. MyClass objects[10] is made of ten MyClasses side-by-side, no pointer involved.
When you write objects[0] = MyClass(/* ... */);, you are constructing a new MyClass, then assigning (copying) it to the first MyClass in the array, then destroying it. Again, no pointer involved.
Now my question is will the first objects[0] memory be freed when I change object[0] to the other value?
No. Throughout the lifetime of the array, the 10 objects are the same. No objects are ever added or removed. The memory of all the objects (not counting dynamic memory that they may own) is allocated when the lifetime of the array begins, and freed when the lifetime of the array ends.
When you assign to one member of the array, the copy (or move) assignment operator changes the state of the object within the array. The temporary object that was copied from, is destroyed at the end of the assignment.
As far as I understand an object is basically a pointer to the fields of the class
That seems misleading to me. A better analogy is that an object is a block of memory, and the member objects are sub-objects within that memory block. Just like array is a block of memory, and members of the array are sub objects within that memory block.
Your pointer analogy would be appropriate in some languages like Java where non-primitive variables are implicitly pointers. But not in languages like C++, where pointers are explicit, and value semantics are used implicitly.
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 have an array of pointers: pArray[rows][columns], where each element can contain a pointer to an object. Some of the objects were instantiated in main() on the heap, and some were instantiated by objects themselves also on the heap: That is, I passed pArray to an object member function, and that function created a new object, and put a pointer to it in pArray.
Now when I want to delete pointers to objects from pArray, is there ownership in play here? Meaning, if an object created a new object and placed a pointer to it in pArray, can only the creator object call delete on that pointer? Or can I do it from main(), and other objects by passing the array to them?
Some more details:
The code simulates a predator prey model on a grid (pArray). So I begin by reading in the initial grid config from a file, and instantiate objects (predators, and prey), on pArray from main(). But predators and prey can breed, so objects spawn new objects and by passing pArray to them, they instantiate their children on pArray.
With raw pointers ownership is purely a concept. As long as you are working with raw pointers, it is entirely up to you to assign ownership of pointed object to anyone and anything. It is a matter of your design. There's no such "rule" that the object should be deleted by whoever created them. Ownership can be retained or passed on. Ownership can be shared (as in reference-counted ownership schemes). Again, it is a matter of your design and your intent.
Various smart pointer classes will help you to express your intent and implement your intent. With raw pointers you have to remember who owns what and do everything manually.
No, there is no "ownership" on pointers in C++, if the pointer is valid (contains proper reference to data / object), you can deallocate it anywhere issuing delete command.
The destructor of objects is subject to the same public/protected/private like every other method. So, if the destructor is public, anyone can call delete on the object.
The only important thing is that it happens exactly once, and only after nobody is using the object anymore.
There is no ownership concept for pointers in C++ .As far as I understood your question, Yes you can delete that object from main() in case of dynamic memory allocation. The memory allocated to that object would only be freed only when the program ends or the Object array goes out of scope and the destructor for the class is called.
I've a method in a class that get's a pointer to another object (of a different class)and adds an object (of another different class) to a vector that is a member variable of the first object (the one that is passed as a parameter). This is the code:
ObstacleManager::ObstacleManager(Application *lApp)
{
app=lApp;
GLfloat obstacleVerts[12]={
-0.1f,-0.2f,0.0f,
0.1f,-0.2f,0.0f,
-0.1f,0.2f,0.0f,
0.1f,0.2f,0.0f
};
StandardObstacle obstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle.manager=this;
lApp->characters.push_back(&obstacle);
}
I think the problem is that the obstacle object gets released when it shouldn't, because if I change the code and create the obstacle with a "new" (if you create an object with new you have to manually delete it, don't you?) It works. Like this:
ObstacleManager::ObstacleManager(Application *lApp)
{
app=lApp;
GLfloat obstacleVerts[12]={
-0.1f,-0.2f,0.0f,
0.1f,-0.2f,0.0f,
-0.1f,0.2f,0.0f,
0.1f,0.2f,0.0f
};
StandardObstacle *obstacle=new StandardObstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle->manager=this;
lApp->characters.push_back(obstacle);
}
Is there a way to prevent this from happening?
You are passing the address of a local object to the vector, the local object does not exist once the constructor returns and your vector then has a pointer which points to invalidated memory.
You will have to make the object persist, possible ways are:
Just push the object by value or
Use dynamically allocated object but instead of raw pointer use a smart pointer like shared_ptr as the vector element type.
Yes, you either create the object with new or use smart pointers instead.
Your intuition is correct:
ObstacleManager::ObstacleManager(Application *lApp)
{
//...
StandardObstacle obstacle(obstacleVerts,-0.7f,0.0f,4);
obstacle.manager=this;
lApp->characters.push_back(&obstacle);
} //obstacle is destroyed here
The object obstacle is created in automatic storage. Its lifetime is limited by its enclosing scope, which is the closing bracket in the constructor.
So you take the address of an object, push it into your vector, and then the object is destroyed. That means that, inside the vector, you now have a dangling pointer.
This will most certainly lead to undefined behavior.
You can either use new, as you have, and make sure to clean up the memory. Or you can use smart pointers - which is more C++-ish than raw pointers.