Similar to the concept of GC in Java, when an object is not referenced anymore by something else, it gets marked for GC.
Does unique_ptr work similar to this?
If say I have a data structure (a tree) with nodes containing left/right std::unique_ptr<BSTNode>. Say I have a remove function remove(std::unique_ptr<BSTNode>& root, int val), if I go to the parent of the BSTNode containing val, and assign nullptr to the left or right child field (which is the std::unique_ptr<BSTNode> containing val), would the smart pointer self destruct?
Or should I reset the smart pointer inside of the remove function as well? This question is mostly a scope issue that I am not understanding.
if I go to the parent of the BSTNode containing val, and assign nullptr to the left or right child field (which is the std::unique_ptr containing val), would the smart pointer self destruct?
The smart pointer will destroy the thing it points to.
It will not destroy itself (which is what self-destruct means; you may have confused terminology here).
The key to unique_ptr is understanding the lifespan of stack variables.
There's nothing inherent in unique_ptr that's different from other stack variables, just the use of its destructor to clean up the owned content. This is an idiom widely used before these pointers, referred to as RAII Resource Acquisition Is Initialisation.
If you have a unique_ptr on the stack, ie: declared inside some scope, it executes its destructor when you exit that scope and the stack variables are deleted.
If you have it inside some struct or class allocated on the heap, it executes its destructor when that container is deleted.
Related
I'm doing a project for the university and im trying to find out how to delete memory properly and if the way of deleting that i came up with will have the same effect as using smart pointer.
This is a class that will hold all employees working in the company and teams which basically have vector of pointers to some of the employees.
class Company
{
private:
std::string companyInfo;
std::vector<Employee * > employees;
std::vector<Team *> teams;
public:
Company();
~Company();
std::string getCompanyInfo() const;
void setCompanyInfo(const std::string & companyInfo);
bool addEmployee(Employee * employee, const std::string & teamName);
bool addTeam(Team * team);
void printTeams() const;
void printEmployees() const;
};
So my question is : Is this a proper way of freeing the memory and if its is will it provide the same result as using smart pointers to automate the process.
Company::~Company()
{
for (Employee * e : employees) {
delete e;
}
employees.clear();
for (Team * t : teams) {
delete t;
}
teams.clear();
}
If it's better practise to use smart pointer should i use unique or shared pointer in my particular case. I have red about smart pointers and that they delete the allocated memory when the scope end but i'm really confused when will end. Is this going to happen when the destructor of company is called?
Thanks in advance and sorry if my questions look stupid.
You should never write delete in your code logic if you don't know what you're doing. That's the rule. Whenever you break this rule, expect all kinds of problems to happen. In other words: Always use std containers + smart pointers.
Unique pointer: A simple wrapper around your pointer that will delete the resource under it when it goes out of scope. You can't copy unique pointers, because then who will hold the ownership of the pointer if you can? Who will delete it? Only 1 object should be able to delete it.
Shared pointer: Makes copying possible, but at the expense of having an (atomic) counter that counts how many objects refer to the same pointer. When the counter goes to zero, the resource under the pointer is deleted.
Is this a proper way of freeing the memory
Assuming that the containers are filled with the new operator like this,
employees.push_back(new Employee());
teams.push_back(new Team());
then yes, this is the correct way to clean up these resources.
... and if its is will it provide the same result as using smart pointers to automate the process.
Generally yes. You can tweak how a smart pointer does its job of deleting the resource it manages, but the default behavior is the correct one for your case (call delete).
should i use unique or shared pointer
The first choice should be std::unique_ptr. It's more efficient than std::shared_ptr and is more restrictive on how the object it manages can be used. But this comes with limitations, e.g. a class with std::unique_ptr data members (like Company in your case) can't be copied. Using std::shared_ptr instead mitigates this issue, but comes with very different semantics - copying a Company object then means sharing teams and employees. This might not be what you want. One way around this issue is to go with std::unique_ptr, implement copy and copy assignment constructors for Company in terms of so-called virtual constructors Employee::clone() and Team::clone() member functions.
they delete the allocated memory when the scope end but i'm really confused when will end
An example:
void someFunction()
{
Company c;
// stuff...
} // the scope ends here, ~Company will be called
Is this a proper way of freeing the memory
The destructor is OK, assuming all of the stored pointers have been allocated using a new-expression, and assuming that all of them are still valid i.e. not dangling.
Clearing the vectors is redundant though. The vectors are about the be destroyed immediately, so their elements are going to be cleared anyway.
However, your class is most likely broken. It is copyable, and if you make a copy, and don't remove the pointers from one of the copies, then the destructors of those objects will delete the same pointers which will result in undefined behaviour.
You can fix this problem, as well as make your destructor simpler (you can simply use the implicit destructor) by using smart pointers.
should i use unique or shared pointer
Yes, you should.
Your code demonstrates unique ownership - Company owns the Employees and Teams uniquely - so the simplest change is to use unique pointers.
I have red about smart pointers and that they delete the allocated memory when the scope end but i'm really confused when will end. Is this going to happen when the destructor of company is called?
It is the destructor of the smart pointer that deletes the pointer.
When the smart pointer is a local variable, it is destroyed at the end of the scope. Just like if your Company is a local variable, it is destroyed at the end of scope, and its destructor will be run.
When the smart pointer is a member, it is destroyed when the super object is destroyed. In your case, you'd have a vector of smart pointers, in which case the smart pointer is destroyed when the vector is destroyed, or the smart pointer is erased from the vector.
In my method a Player object is created like:
Player player(fullName,age);
My teacher gave us a piece of code with a constructor that takes a shared_ptr to a player object.
//constructor of the class
SomeClass(const std::shared_ptr<Socket> client, std::shared_ptr<Player> player)
Lets say we want to call the constructor of SomeClass and pass the player object we created on stack.
Is it ever safe/possible/good to create a shared_ptr from a stack object?
To make the question more understandable lets say we have two big code projects and we want to merge them so a method from one project is called from another one, should we rewrite all the files to use shared_ptr or stack objects exclusivly (for the methods that needs to be connected) or should we just create a shared_ptr to the stack object.
Why im not sure of the result:
What if the scope where the stackobject is created ends but the shared_ptr is still used and vise versa.
The stackobject gets deleted when out of scope or does it stay alive because there is still a reference to the object (in another class though)?
The shared_ptr goes out of scope and tries to delete the object, can it even though the stackobject is refering to it?
Note: I know I could just use the following and pass player
shared_ptr<Player> player{ new Player {fullName,age} };
Is it ever safe/possible/good to create a smart_ptr from a stack object?
Safe? Only if you can guarantee that the stack which created that object will only be ended after all shared_ptr's that pseudo-own it.
Possible? Sure: pass shared_ptr's constructor a deleter object that does nothing:
auto sptr = shared_ptr<Player>(&player, [](Player *) {});
When the last shared_ptr is destroyed, the deleter will be called and nothing will be deleted.
Good? Not really. As noted above, safety is not something that can be universally guaranteed in such code. Depending on your code structure, this may be legitimate. But it requires great care.
This SomeClass is expecting to claim ownership of a resource; that's why it's taking a shared_ptr. You're kind of lying to it by passing it a shared_ptr that doesn't really own the object it references. That means the onus is on you and your code structure to not violate the promise you made to SomeClass that it would have shared control over that object's lifetime.
The purpose of a shared pointer is to manage the lifetimes of dynamically created objects. As long as there is any shared pointer that points at an object, that object must still exist; when the last shared pointer that points at an object is destroyed, that object gets destroyed.
Stack objects have a fundamentally different lifetime: they exist until the code exits from the scope in which they were created, and then they are destroyed.
The two notions of lifetime are incompatible: there is no way a shared pointer can ensure that a stack object that has gone out of scope still exists.
So don't mix the two.
Is it ever safe/possible/good to create a shared_ptr from a stack object?
I agree with #Nicolas Bolas that it is not safe. But it may be safe to create a shared_ptr from a copy of a stack object
shared_ptr<Player> playerPtr(new Player(player));
if Player is copy-able of course.
It's not safe to create a shared pointer to a stack object, because the stack object is due for destruction as soon as its containing function returns. Local objects are allocated and deallocated implicitly and automatically and trying to intervene is surely invoking many kinds of undefined behavior.
Use move semantics to create the shared_ptr
std::shared_ptr<Player> player_shared_ptr{ std::make_shared(std::move(player)) };
In this way, a copy is avoided. You may need to implement move constructor though on relevant classes for this approach to work. Most/all std objects support move semantics out of the box (eg. string, vector, etc.)
Safe is a strong word.
However, You can make the code safer by defining a StackObjectSharedPtr, forcing the shared_ptr instanciated type to include a "special" StackObjectDeleter
using PlayerStackSP = std::shared_ptr <Player, StackObjectDeleter> ;
class StackObjectDeleter {
public:
void operator () (void*) const {}
};
Player player(fullName,age);
std::shared_ptr<PlayerStackSP, StackObjectDeleter> player(&player, StackObjectDeleter());
The StackObjectDeleter replaces the default_delete as the deleter object. default_delete simply calls delete (or delete []). In case of StackObjectDeleter, nothing will happen.
This is a step further of #Nicol Bolas's answer.
I am writing a quad tree which stores pointers to collidable objects in an stl list.
I want the quad tree to be able to move the objects from node to node depending on their position in the world, and would like to just get something confirmed:
If I remove the pointer from the list, to insert the object into another tree node (such as the parent tree node), will the destructor for the pointed-to object be called? For clarification, I do not want the object destroyed, as it is used & managed elsewhere in the program.
Thanks, in advance.
The actual object in the list (i.e. the pointer) will be destructed, but not what the pointer points to.
It might be a little confusing to begin with, but if you see the pointer, and what it points to, as completely separate entities it makes a lot more sense.
The destruction of an object is determined by its storage duration. If an object has automatic storage duration (like a local variable), it will be destroyed when it goes out of scope. If an object is dynamically allocated (using new), it will only be destroyed when you do delete on it. If it has static storage duration, it will be destroyed when the program ends.
If you are just copying the pointer out of one node and into another and as long as the object it points at hasn't been destroyed according to the above rules, the pointer will continue to point at the same valid object.
no, destructors are never called on pointers in STL. It only gets destroyed when you call delete explicitly on the object pointed to (or if the object when stored on the stack goes out of scope) or if you use smart pointers.
I'm not sure if what you say will happen, but anyway it might be a good practise to reset your pointer to NULL before deleting the instance. Also, remember to make the pointed-object to be pointed by the correct node, that probably will be the node that was pointing to the node you erased.
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.
When you create some pointers inside the scope of a function, what happens when the function goes out of scope? Do they get destroyed or should I call delete on them at some point?
void XMLDocument::AddNode(XMLNode& node)
{
std::string val = node.GetNodeName();
TiXmlElement* el = new TiXmlElement(val.c_str()); // What about this object ptr?
TiXmlText * txt = new TiXmlText(node.GetNodeValue().c_str()); // And this one?
el->LinkEndChild(txt);
document.LinkEndChild(el);
}
Normally, you need to call delete on both the pointers in order to avoid memory leaks. But in you case, it looks like you are putting this pointer in a document object (I am assuming document stores the pointer itself and will not create copy of the pointed to object itself). So if you call delete here, the pointer you have given to the document object will be invalid one. So if document object takes ownership of deleting the memory you allocated in this function, then you should not call delete here, else if it is creating the copy of the object you passed, then you need to delete it here. Using a smart pointer will be quite useful in these type of scenarios. Take a look at boost::shared_ptr for more details.
The only thing that can be stated for sure is that immediately after the exit of this function, neither of those pointers has been returned to the heap.
What happens after the function exits depends on the contract for memory usage that is implied by passing a pointer into LinkEndChild. Do you still own the memory after this, or does it get cleaned up when the new parent (in this case document, which accesses the memory directly for el, and via el for txt) is cleaned up? If the former, then you are correct not to delete it. If the latter, then at some point you need to clean it up, presumably after document (global? class member?) is done with.
A further nuance is what is the contract on construction of TiXmlElement and TiXmlText - do they copy the input C-string, or use them by reference?
I would guess that it's XmlDocument's doc to clean up all memory that is linked into the document. Kind of messy, though. Check the destructor XmlDocument::~XlmDocument, see if it walks a list of children cleaning them up (recursively).
EDIT: This looks like TinyXML, in which case it's supposed to clean up all the memory you give it on destruction. See here for a discussion : http://www.gamedev.net/community/forums/topic.asp?topic_id=518023
The semantics of TinyXML clearly imply
that (a) it owns the document tree,
and (b) you pass in nodes that you
allocate. I can see no good argument
for it not simply using the delete
operator on everything linked into it.
EDIT: In fact, given that TinyXML (or
at least the copy I have here) clearly
has while ( node ) { temp = node; node
= node->next; delete temp; } in the TiXMLNode destructor, I'm guessing
this is just a bug in the TinyXML++
wrapper.
See also previous Stack Overflow question about TinyXml memory management here.
The documentation for LinkEndChild
says this:
NOTE: the node to be added is passed
by pointer, and will be henceforth
owned (and deleted) by tinyXml. This
method is efficient and avoids an
extra copy, but should be used with
care as it uses a different memory
model than the other insert functions.
When you use new, memory from the heap is allocated, while the objects locally declared in a function are allocated on the stack.
The objects allocated to the stack stop to exist after the method call.
In your case TiXmlElement* el is a pointer allocated on the stack that references memory on the heap. Once you leave the function, the el pointer will stop to exist (since it was on the stack) but the memory that it referenced, still exists (was on the heap). So if that memory is not "freed", it is considered as "leaked"