I'm trying to make a List class using the concept of linked lists, and while I was originally using the C++ standard new keyword, I decided to switch it out for the C++11 std::shared_ptr. However, I can't get the program to function properly when using smart pointers, as it crashes. Here are some bits of code before the change:
class List
{
public:
void push_back(...) {
Node *temp = new Node;
...
if (!head) {
head = temp;
return;
}
else {
Node *last = head;
...
last->next = temp;
}
}
...
private:
Node *head = nullptr;
};
And here's what it looks like with the change:
class List
{
public:
void push_back(...) {
std::shared_ptr<Node> temp(new Node);
...
if (!head) {
head = temp.get();
return;
}
else {
Node *last = head;
...
last->next = temp.get();
}
}
...
private:
Node *head = nullptr; // don't need this to be a smart ptr
};
I feel like the problem might be that head and last aren't dynamically allocated and maybe they need to be to work with a shared_ptr, but I'm not sure. What exactly am I doing wrong and how can I fix it? I really hope this isn't a duplicate because I can't seem to find anything that solves my problem. Thanks.
Edit:
Here's the Node struct:
struct Node{
int data;
Node* next;
};
The reason to have std::shared_ptr in the first place is to have std::shared_ptr take complete and full ownership of the pointer, and make it std::shared_ptr's responsibility to delete it, once the last reference to the pointer goes away. That's what std::shared_ptr is all about.
This means that once a pointer is placed into a std::shared_ptr, the std::shared_ptr now takes complete and full responsibility of managing the pointer. It owns it completely.
It, therefore, makes no sense to put a pointer into a std::shared_ptr ... and then immediately take it out:
head = temp.get();
There are reasons for the get() function to exist, but this isn't one of them.
In order to use std::shared_ptr correctly, everything must be a std::shared_ptr. head needs to be a std::shared_ptr:
std::shared_ptr<Node> head; // yes, it does need to be a smart ptr
Why does it need to be a std::shared_ptr? Well, if it's not, what do you think will happen when this:
std::shared_ptr<Node> temp(new Node);
Specifically, when this temp smart pointer gets destroyed, when this function returns? Well, since it will be the last std::shared_ptr that referenced this Node, it will happily delete it. The fact that you get() it earlier, and placed it into head doesn't matter. So now you have a head that points to a deleted Node. Hilarity ensues.
And this is why everything must be a std::shared_ptr. Not only head, but also Node's next member also needs to be a std::shared_ptr, too.
Now, there is a pitfall involving circular references, that comes into play when std::shared_ptr enters the picture. But that's going to be a different question.
Your main issue is that if you're going to use shared_ptr, best to use it all the way. Make next a shared_ptr instead of a raw one.
struct Node {
int data;
std::shared_ptr<Node> next;
}
What std::shared_ptr does under the hood is keep a count of how many references there are to a pointer. When you use copy constructors or operator= it increases a reference count. When an instance falls out of scope resulting in the destructor being invoked (or you give it a different pointer with operator=) the reference count decrements. When the count is zero the pointer is destroyed.
// pass by value invokes copy constructor (refcount + 1)
void myFunc(std::shared_ptr<MyClass> var) {
// Code using var
} // end of function invokes destructor (refcount - 1)
void run() {
std::shared_ptr<MyClass> ptr(new MyClass); // refcount = 1
myFunc(ptr); // refcount = 2
// After myFunc returns refcount = 1
}
int main() {
run(); // refcount = 1
// After run returns, refcount = 0 and the pointer is deleted
}
By using get() you introduce a pointer to memory that may be deleted at some point, regardless of whether or not that pointer is around. This can lead to segfaults as the raw pointers are pointing to memory that shared_ptr deleted.
This is because get() does not affect the reference count. How could it? It's not a shared_ptr any more so that class definition has no way of knowing what you do with it, or when it gets deleted. If get() increased the reference count there would be nothing to decrease it afterwards, and the memory would never be released. That's a memory leak!
Related
Im having difficulty describing this problem succinctly so be kind.
I have a Tree object that has an attribute root which is a pointer to a node object. When I initialize the Tree object the root is unknown so i assign it to a nullptr.
In a function after some computation I find the root node of a complete binary tree. I now want to hand this value over to my Tree.root pointer. However since this function is removed from the stack after execution and Tree.root pointer appears empty when I run it later.
class Tree{
public:
Node *root;
Tree(){
root = nullptr;
}
};
void worker(Tree *t){
// Perform some computation
// Since the var rootFound only exists in this function.
// After executing doesn't the memory address reallocated
// and therefore the root points to an unknown memory address?
t-> root = &rootFound;
}
int main(){
Tree t{};
Tree *ptr = &t;
worker(t);
// t pointer is null
return 0;
}
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value. Also since any node has left and right Node pointer Im not sure if the pointers lose the memory address they are pointing too or if they too will be added to the heap.
I could also just be overthinking this.
Since you posted an incomplete code in your question, I will be forced to assume things.
I will assume your implementation look like this:
void worker(Tree *t){
Node rootFound;
// do stuff where eventually rootFound = something
t->root = &rootFound;
}
In this case, yes, t->root will point to a dead object once worker is finished.
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value.
There is two kind of raw pointer in C++: owning pointer and non owning pointer.
If t->root is a owning pointer, it means you will call delete on it.
If t->root is not a owning pointer, it means you will not call delete on it.
Then if it is owning, you can totally do new Node{...} an assign to it.
If on the contrary it is not and you want to create an new tree in this function and delete it later, you will need to give an owning pointer back to the caller, something like this:
Node* worker(Tree* t) {
Node* rootFound = new Node{}; // create a whole new tree here
t->root = rootFound; // assign it to the tree
return rootFound; // return a owning pointer to the caller
}
Then, in your main:
int main(){
Tree t{};
Tree *ptr = &t;
Node* owning = worker(ptr);
// do stuff with t
// delete the owning pointer.
delete owning;
return 0;
}
Of course, there is a better way to separate owning and non owning pointer.
In modern C++, owning pointer are declared like this: std::unique_ptr<T> and non owning are written T* and assume you don't have to delete it.
If we change your data structure just a little bit to express what pointer is which, it would look something like this:
class Tree{
public:
// Here! Root is owning.
std::unique_ptr<Node> root;
Tree(){
root = nullptr;
}
};
// Tree is non-owning, so we write it just like before.
void worker(Tree* t){
// ...
}
The neat thing about std::unique_ptr is that is clears memory in its destructor so you don't have to worry about deleting:
int main() {
// make_unique will call new
std::unique_ptr<Node> node = std::make_unique<Node>();
// Here, unique_ptr will call delete
}
So in the end, Tree will clear up itself at the end of main:
int main(){
Tree t{};
Tree *ptr = &t;
// worker can do t->root = std::make_unique<Node>();
worker(ptr);
return 0;
// Here, t.root will call delete if not null
}
I have a class that contains a structure called Node and memory for this is dynamically allocated. Using the add function I am creating more Node and connectin them through the next array pointers. I am only saving my head pointer, which points to my first node. I am trying to write a destructor like below. Is it ok?
struct Node{
bool arr[30];
bool end[30];
Node* next[30];
};
class ClassName{
Node *head;
Node* newNode(){
Node * cur = (Node*)malloc(sizeof(Node));
return cur;
}
public:
ClassName(){
head = newNode();
}
~ClassName(){
free(head);
}
void add(string s,int pos,Node *cur){// 1 base index
// adding new node and next array pointers will connect them
// So after adding some nodes it will form like a tree
}
};
~ClassName(){
free(head);
}
This frees the head node. It doesn't also free any of the nodes referred to by head->next[0..29]. So no, it's not OK if you actually allocated those nodes - you will have a memory leak.
Next problem, your next array is uninitialized, so unless it's always all populated (which is obviously impossible as your tree would have no leaves), there's no way to figure out which entries are real pointers and which are garbage values. So it's impossible to fix this leak with the code as shown.
We could fix the existing malloc code to properly initialize your objects, but it brings us on to the next oddity, which is using malloc and free for objects in C++ at all.
Using new and delete would be a modest improvement (at least Node could have a constructor and destructor to properly initialize and destroy itself), but switching to owning smart pointers instead of raw pointers would be best: they initialize and destroy themselves automatically with no extra work on your part.
struct Node{
// value-initialize all those bools to false
bool arr[30] {};
bool end[30] {};
// this will initialize all entries to nullptr, and
// also takes care of deleting them on destruction
std::array<std::unique_ptr<Node>, 30> next;
};
std::unique_ptr<Node> ClassName::newNode() {
return std::make_unique<Node>();
}
The best way is to use smart pointers. But if you would like to stick to built-in pointers, it is also very easy to achieve the goal. You only need to add a simple one-liner destructor for every class, and make sure every destructor frees memory at its own level. Then the class relationship guarantees that the memory are freed in a recursive postorder manner. The beauty of this approach is that you don't have to write a recursive postorder traversal yourself. The destructors recurse themselves.
Add the following destructor for Node class:
~Node() {
for (Node *p : next) {
delete p;
}
}
Use the following destructor for ClassName class:
~ClassName(){
delete head;
}
A note: To verify that the nodes on the tree are freed in a postorder manner, you may add a print statement after each delete statement.
I'm new to C++ and I found out that I have been spoiled by Java and newer programing languages like Swift. So I understand that sometimes you have to delete objects manually in C++ such as pointers. You can use the delete keyword or you can use the smart pointers. But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
I'm writing code that acts as a integer linked list. So I have a pointer pointing to the head and the tail of the list. When ever someone 'polls' something it should delete it from the list and then reset the head (or tail) accordingly. So I have some code that works fine for what I need it to do:
int IntegerLinkedList::pollFirst(){
if (tail == nullptr && head == nullptr) {
return 0;
} else if (head == tail) {
int ret = head->getData();
head = nullptr;
tail = nullptr;
//delete head;
//delete tail;
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData();
//delete head;
head = newHead;
return ret;
}
}
But I never really delete the object that it was pointing at, I just remove all the pointers to it. Does that delete the object like it would in Java? Or do I have to manually delete it and how would I do that? Am I memory leaking??? Thanks so much
Also the code that updates the head is
void IntegerLinkedList::addFirst(int x){
IntegerNode* n = new IntegerNode(x);
if (head == nullptr && tail == nullptr) {
head = n;
tail = n;
} else {
head->setPrevious(n);
n->setNext(head);
head = n;
}
}
And the head was defined in the header as
IntegerNode* head;
Java has a garbage collector that essentially does what smart pointers do. That is, when the last reference to an object falls out of scope clean up the memory.
The delete keyword frees up the memory at a location the pointer points to. It doesn't actually do anything to the pointer variable itself (which is just an address).
The way to correct your code would be:
else if (head == tail) { // suppose head = 0xAD4C0080
int ret = head->getData();
delete tail; // cleans memory at 0xAD4C0080, head and tail are still 0xAD4C0080
head = nullptr; // now head = 0
tail = nullptr; // now tail = 0
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData(); // obtain data while head still exists
delete head; // get rid of head
head = newHead; // remove stray reference to deleted memory
return ret;
}
If you attempted to use the value 0xAD4C0080 after calling delete in these examples you would get a segmentation fault.
As for smart pointers (quoting from your comment):
yes the smart pointers, but do they delete what it is pointing at or just themselves
Smart pointers delete what they are pointing to when they themselves get deconstructed (usually by falling out of scope). i.e.
void func() {
std::unique_ptr<int> pInt(new int);
} // pInt falls out of scope, std::unique_ptr<int>::~std::unique_ptr<int>() called
I'm confused on whether that deletes the pointer itself, so the
pointer can't be pointed again or if it deletes where the pointer is
pointing.
It deletes what the pointer is pointing to. The pointer must be pointing to an object that was allocated with dynamic scope (the new keyword).
I just remove all the pointers to it. Does that delete the object like
it would in Java?
Of course not.
Or do I have to manually delete it and how would I do that? Am I
memory leaking???
You have to manually delete it, using the delete keyword, and, yes, you are leaking memory unless you do that.
It is often said that it's easier to learn C++ from scratch, than to try to learn C++ if you already know Java. C++ objects work fundamentally differently than they work in Java.
And not only differently, but in ways that have no equivalent in Java, at all. There is no Java equivalent, for example, of an object instantiated in automatic scope, in C++.
The full explanation of various scopes of C++ class instances cannot be fully given in a brief answer on stackoverflow.com. You need to get a good book on C++, and start reading it.
And forget everything you know about classes from Java. C++ classes don't work that way. The longer you keep trying to draw analogies with Java, the longer it will take you to learn how to use C++ classes correctly.
Yes, some of the pain can be helped by using smart pointers, which will take care of some of the pain points. But understanding smart pointers in of themselves also requires complete understanding of C++'s class model. Smart pointers do not solve everything, and it is important to understand how C++ classes work, in order to understand what problems smart pointers do solve, and what problems they do not solve.
It depends on what the type is for head and tail. In C++, there are operators (e.g., operator=), and there are destructors. This can lead to certain interesting consequences. Take this example:
#include <memory>
int main() {
// allocate memory
int* ptr = new int;
// store in smart pointer
std::unique_ptr<int> smart_ptr(ptr);
// create another wrapped pointer
std::unique_ptr<int> smart_ptr2(new int);
// throw away location of allocated memory
ptr = nullptr;
// free memory by assigning to smart pointer
smart_ptr = nullptr;
// we can call delete safely here because ptr is null
delete ptr;
// data pointed to by smart_ptr2 will
// be deleted at end of scope
return 0;
}
Additionally, there are two operators for allocating memory, operator new and operator new[], which must be free'd using delete and delete[] respectively.
A more detailed explanation of these concepts may be beyond the scope of this site.
Am I memory leaking???
Yes, if you new something, you must delete somewhere. Assigning pointer to nullptr won't ever affect the allocated data.
But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
The delete keyword will delete the content at the address you send to it. It won't delete named variable, as variable on the stack are destructed at the end of the scope. Deleteting manually something with automatic storage led to undefined behaviour.
I see you are confused about std::unique_ptr No, they are not deleting themselves. Like any other variable, thier destructor are called and the variable is destructed. The thing about std::unique_ptr is that in their destructor, they delete the data they point to, with you having to delete it yourself. You should read about the RAII idom.
There's a thing about your code, these lines in particular:
head = nullptr;
tail = nullptr;
delete head;
delete tail;
This won't do a thing. You are deleting no data, as head and tail point to nothing. Since the delete keyword deletes the data pointer are pointing to, it won't delete anything.
However, take this example with std::unique_ptr:
{
std::unique_ptr<int> myPtr;
myPtr = std::make_unique<int>(); // or you can use `new int;`
myPtr = nullptr; // The old int you allocated with `std::make_unique` is deleted.
myPtr = std::make_unique<int>(); // assign a newly allocated int
}
// Here, myPtr will free his data as it leaves the scope.
If you use the new keyword, then you always need to use delete. Memory allocated using new is not managed.
Currently your program is leaking memory in the pollFirst method, because you do not free the memory that head and tail point to before re-assigning them. You can do this by calling delete head and delete tail before re-assignment.
You should look into using one of the smart pointer types, such as unique_ptr, if you want automatic management of the memory your pointers point to.
There are few things you should know about C++.
Destructor (DTOR) : Destructor is something which you define for your class. If you don't define a destructor of your own compiler does it for you.
When you call delete for a pointer the DTOR of that class is called which does the necessary cleanup. In order to test it, please put a breakpoint to the DTOR and run the code. Once the control hits DTOR, check the call stack, you will find out that last frame below the DTOR in call stack is the line where you call delete.
As far as the smart pointers are concerned, it does something similar to the garabage collector. Smart pointers have something called reference count. The moment reference count of a smart pointer goes to 0, the DTOR is called.
NOTE: It is advised to write your own DTOR if you have a data member in the class which is pointer.
Suppose I have a doubly-linked list defined by the class
class list
{
/*...*/
private:
struct node
{
node* prev;
node* next;
int* value;
}
node* first; //NULL if none
node* last; //NULL if none
/*...*/
}
If I wanted to make a destructor for this list do I have to explicitly delete the value?
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move;
move = first;
}
}
Would the above work to ensure that no memory is leaked? Or do I have to do:
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move->value;
delete move->prev;
delete move;
move = first;
}
}
I'm confused as to how I can make sure that no memory is leaked in this case. How do I deal with the pointers in the nodes specifically? If I delete move does it automatically take care of these?
You need to pair each new with exactly one delete. That is, you probably don't want to delete prev (this node already was deleted) but you want to delete value. Well, I'd embed the value into the object and not point to it:
struct node
{
node* prev;
node* next;
int value;
};
If the value absolutely needs to be a pointer, I'd use a std::unique_ptr<int> (or, if you need to use C++ 2003, a std::auto_ptr<int>).
For each successful new expression, call delete exactly once on that object.
For each successful new[] expression, call delete[] exactly once on that object.
That means that neither of your cleanup functions are OK:
The first function forgets to delete the value, which means a memory leak.
The second function, by deleting both move and move->prev at each node in the list, risks deleting most nodes twice, which is Undefined Behavior.
To avoid the memory leak for the first function, simply store the integer directly instead of allocating it dynamically.
Whether you have to delete the memory pointer by the value member - only you can know. It is a question of memory ownership, a question of your design. If the list owns the data memory pointed by the value members, then you have to delete it in the list destructor (i.e. when the list dies, the data it owned dies with it).
If the list does not own the value memory, then you are not supposed to delete it. Again, only you can answer the question of whether your list is supposed to own the value memory. It is a matter of your intent.
Now, as for the memory occupied by node objects, it is obviously owned by the list, so it has to be carefully deallocated in the destructor. The first version of your destcructor is close to being correct (the second makes no sense at all), except that it written in a slightly obfuscated fashion. This should be sufficient
list::~list()
{
while (first)
{
node *move = first;
first = first->next;
delete move;
}
}
(Again, if you have to delete value, then delete move->value should be added to your cycle before delete move.)
P.S. Once you get this, you might want to look into various smart pointer classes, which allow you to explicitly express memory ownership relationsips, thus making them known to the compiler. When used properly, they will make memory management almost automatic.
In the following code, I am getting the following runtime exception (possibly memory leak) after return 1; and in destructor of Node().
Unhandled exception at 0x0f9bad4a (msvcp100d.dll) in test.exe: 0xC0000005: Access violation reading location 0xfeeefef2.
It's been a while since I used smart_ptr, so am trying to learn what am I doing wrong here ?
#include <vector>
#include <queue>
#include <memory>
#include <iostream>
using namespace std;
class Node;
typedef shared_ptr<Node> SharedNode;
class Node {
Node* parent;
vector< SharedNode > children;
int value;
//limiting construction
Node(int a_value):value(a_value),parent(0){}
Node(const Node ©); //non-construction-copyable
Node& operator=(const Node& copy); //non-copyable
public:
static SharedNode create(int a_value){
return SharedNode(new Node(a_value));
}
SharedNode addChild(SharedNode child){
child->parent = this;
children.push_back(child);
return child;
}
SharedNode getNode(int searchValue);
};
SharedNode Node::getNode(int searchValue){
// Breadth First Search
queue<SharedNode> que;
que.push(SharedNode(this));
while(!que.empty()){
SharedNode node = que.front();
que.pop();
if(node->value == searchValue)
return node;
vector<SharedNode>::iterator it;
for(it = node->children.begin(); it != node->children.end(); it++){
que.push(*it);
}
}
return 0;
}
int main(){
SharedNode node_ptr = Node::create(5);
for(int i = 0; i < 4; ++i)
node_ptr->addChild(Node::create(i));
cout << (node_ptr->getNode(-1) != 0 ? "Found" : "Not found");
return 1;
}
I think I'm messing up when I use shared_ptr on this, like: shared_ptr(this). But then, that's my guess.
What am I doing wrong here ?
The problem is from
que.push(SharedNode(this));
This creates a new shared pointer that now owns this. However, due to the create() method, there is another shared pointer that owns the same object. This can result in a double delete.
If you have a reason to use a shared pointer in this situation, the correct solution is enable_shared_from_this.
First, change the node definition to this.
class Node : public std::enable_shared_from_this<Node> { ...
Then change the offending line to
que.push(this->shared_from_this());
This causes it to return a shared_ptr that points to the object, but it is shared with the already existing shared_ptr, instead of being two separate shared_ptr objects.
Note, for the use of this->shared_from_this() to be legal, the object must be owned by a shared_ptr. You already have accomplished this via the static create() method, but I wanted to make sure you understood the limitation.
Edit: A brief explanation of shared_ptr ownership.
When you create a shared_ptr from a raw pointer using the constructor, it creates a reference object that contains both a pointer to the object and a reference count, which is used to determine how many shared_ptr objects point to it. A pointer to this reference object is then passed to all copies that are made from that original shared_ptr, with the reference count keeping track of how many shared_ptr objects refer to it.
When you call shared_ptr(this), there is no way for the shared pointer to know that this is owned by another shared pointer, and creates a new reference object. Once the one of them reaches a reference count of zero, the object will be deleted, despite the other shared_ptr reference object still pointing to it, resulting in a dangling pointer and the error you are seeing.
If you only need the children to exist when the parent exists, I would consider changing the Node to simply have a std::vector of other Nodes (remove the pointer). When the highest level node is destroyed via its destructor, it will destroy the vector, which destroys the children nodes, and so-on.
class Node
{
// whatever operations you need...
std::vector<Node> children;
}
Edit: As requested...
If you have a use case where you do really want to have the children outlive the parents, you'll have to deal with the parent pointer, since it could be destroyed before the children. One quick solution is determine if you really NEED the parent pointer, and eliminate it if you don't need it.
However, assuming you still want to retain it, you cannot use shared_ptr here. If you do that, you'll have a circular dependency, and neither will be destroyed automatically, which isn't what you want.
The solution here is to use std::weak_ptr. Basically, it interacts with the shared_ptr reference object in such a way that it doesn't prevent the destruction of the pointed to object.
class Node
{
private:
std::weak_ptr<Node> parent;
// Other constructors.
Node(int a_value):value(a_value),parent() {}
public:
SharedNode addChild(SharedNode child){
child->parent = this->shared_from_this(); // Initialize their pointer using
// your shared pointer
children.push_back(child);
return child;
}
// This function will return a shared_ptr to nullptr (and will evaluate false)
// if you have no parent, or if the parent node has been deleted
SharedNode getParent()
{
return parent.lock();
}
};
Consider what happens with the following code:
Node * dumb_ptr = new Node;
shared_ptr<Node> smart1 = dumb_ptr;
shared_ptr<Node> smart2 = dumb_ptr;
You now have two smart pointers both thinking they own the same object. One of them is going to delete the object, and the other one will try to use or delete that deleted object at some point. The way you fix this is by always creating a smart pointer from another smart pointer or from new. Best to never use any dumb pointers at all - that includes this.
shared_ptr<Node> smart1 = new Node;
shared_ptr<Node> smart2 = smart1;