Reputation: 749
I solve algoritm questions from sites like leetcode, hacker rank or cracking the coding interview. I do most if the questions in c++. So for most of them i have a node struct as below
struct Node {
Node* next;
//for tree
Node* left;
Node* right;
int data;
//ctor
Node(int val) : left(nullptr);.....
};
then i have a function(s) which implements the algorithm
bool someAlgorithm(Node* root) {
//do stuff
}
and finally i create the nodes in the main
int main() {
auto root = new Node(4);
root->left = new ..
root->left->left = new ..
}
I want to incorporate memory management in this kind of solutions. If i use c++11 shared_ptr do i need to provide a destructor ? if yes what should i write in the destructor ? But i found that shared_ptr makes code overly complex and un-understandbale for such small programs.
In general what is the best way to make solving such questions memory safe ?
Upvotes: 2
Views: 1005
Reputation: 2975
If you want memory safety, start by realizing that objects created by new
are a resource, i.e. something that is available in finite quantity in the system, that does not belong to your program, that your program has to borrow (through new
in your case), and to give back (through delete
in your case).
Resource management in C++11 maps this borrow/give back pair to the constructor/destructor pair. An object that borrows a resource through its constructor is said to OWN this resource, and is responsible for giving it back to the system.
Besides constructor and destructor, 4 other special functions participate to ownership:
std::move
), in any case, the object is not going to need its precious, expensively borrowed resources. So the new object can be made a full fledged object by taking ownership of the soon-to-die object's resources making them its own, thereby transferring ownership of the resources to the new object.Therefore, if you read too fast, you may read that you have to reimplement all 6 of them. But this resource management is omnipresent in C++11, and the automatic generation of the special functions is made in a straightforward and sensible way, so that:
C++11 provides some special classes to manage a single resource:
std::unique_ptr
owns a single resource. It owns the resource, so it will release it if it still owns it when destroyed. You can't duplicate the resource, so copying it is disallowed. But the resource can change hands through moving. (loot!loot!loot!) It guarantees a single owner for the resource.std::shared_ptr
lets many objects share ownership of a single resource. You can copy it, and what you duplicate in this case is the ownership rights to the resource. In short, it maintains an appropriate counter on the resource to track how many pointers own it.If you use instances of these classes to manage your allocated memory (as members of classes or as local varialbes), then deterministic resource release will automatically happen.
Upvotes: 0
Reputation: 101
The best way to make a simple problem like this memory safe is to add a destructor to node and delete the root node at the end of the program. Because root is allocated on the stack you will have a memory leak at the end currently.
Here's what the definition should somewhat look like.
~Node() {
//call delete on every pointer in the struct
delete next;
delete left;
delete right;
}
Then at the end of your program you can call delete root
and the dtor will be called, recursively deleting every node below it. Even if you use shared_ptr
or unique_ptr
instead of calling delete
you still need the dtor, otherwise all your child nodes will remain allocated when root is deleted.
Upvotes: 1
Reputation: 15176
If you need node deletion operation as part of your algorithm, you have to implement it yourself. No trick will help you to avoid it.
Deleting all nodes is quite straightforward task, as it requres just another traversing the tree structure, as you probably do anyway during someAlgorithm()
execution.
So, I believe, the overall difficulty won't change much even if you choose manual deletion.
Upvotes: 0