free(): invalid pointer when using get() instead of release() on unique_ptr - c++

I have the following program:
#include <list>
#include <stack>
#include <memory>
struct ChildNode {};
struct value_node_ptr : public std::unique_ptr<ChildNode> {
using std::unique_ptr<ChildNode>::unique_ptr;
using std::unique_ptr<ChildNode>::reset;
};
struct Node {
std::list<value_node_ptr> children;
void addChild(ChildNode* child){
children.emplace_back(child);
}
};
void iterateChildren(Node* node){
for(auto it=node->children.begin(); it != node->children.end(); ++it){
auto child = it->release();
//do stuff with child
}
}
int main() {
ChildNode child;
Node node;
node.addChild(&child);
std::stack<Node*> nodes;
nodes.push(&node);
iterateChildren(nodes.top());
nodes.pop();
}
This works fine. But if I am using it->get() instead of it->release() in the iterateChildren function, I get the error
free(): invalid pointer
I want to reuse the children at some point and I thought it->release() would destruct the pointer so it won't be usable after, but it seems the pointer is still there, which confuses me.
Furthermore I thought it->get() was the way to go as I just want to get the value and not destruct the pointer. I was thinking that there might be some memory-leak kind of error when calling it->get(), which is why I tried calling it->reset() on each of the children after being done using them, but this did not resolve the error either.
Can someone explain me this behaviour as well as which method I am supposed to use?

ChildNode child;
Node node;
node.addChild(&child);
addChild() constructs a std::unique_ptr from this passed-in pointer.
The sole reason for having std::unique_ptr, and the only reason it exists, is so that newed objects get automatically deleted, to prevent memory leaks. That's its entire mission statement.
std::unique_ptr (and std::shared_ptr too) is not for pointers to objects that are declared in automatic scope, and which will be automatically destroyed when the automatic scope ends. If you are not creating objects with new there is absolutely no reason, whatsoever, to use std::unique_ptr. It does not accomplish anything except to create bugs and memory errors, of this sort.
You'll either need to remove all use of std::unique_ptr (since it doesn't do anything, and only creates problems here), or create all objects with new before assigning their ownership to a std::unique_ptr.

Related

What all should be deleted in the destructor of a class

So it's been a while since I've done any c++ coding and I was just wondering which variables in a basic linked list should be deleted in the destructor and unfortunately I can't consult my c++ handbook at the moment regarding the matter. The linked list class looks as follows:
#include <string>
#include <vector>
class Node
{
Node *next;
string sName;
vector<char> cvStuff;
Node(string _s, int _i)
{
next = nullptr;
sName = _s;
for (int i = 0; i < _i; i++)
{
cvStuff.insert(cvStuff.end(), '_');
}
}
~Node()
{
//since sName is assigned during runtime do I delete?
//same for cvStuff?
}
};
I'm also curious, if in the destructor I call
delete next;
will that go to the next node of the linked list and delete that node and thus kind of recursively delete the entire list from that point? Also, if that is the case and I choose for some reason to implement that, would I have to check if next is nullptr before deleting it or would it not make a difference?
Thank you.
Ideally, nothing: use smart pointers: std::unique_ptr<>, std::smart_ptr<>, boost::scoped_ptr<>, etc..
Otherwise, you delete what's an owning native pointer. Is next owning?
Do you plan to delete something in the middle of the list? If yes, you can't delete in the destructor.
Do you plan to share tails? If yes, you need reference-counted smart pointers.
It's okay to delete nullptr (does nothing). In the example, you shouldn't delete sName and cvStuff as those are scoped, thus destroyed automatically.
Also, if this is going to be a list that can grow large, you might want to destroy & deallocate *next manually. This is because you don't want to run out of stack space by recursion.
Furthermore, I suggest separating this to List, meaning the data structure and ListNode, meaning an element. Your questions actually show this ambiguity, that you don't know whether you're deleting the ListNode or the List in the destructor. Separating them solves this.
An object with automatic lifetime has it's destructor called when it goes out of scope:
{ // scope
std::string s;
} // end scope -> s.~string()
A dynamic object (allocated with new) does not have it's destructor called unless delete is called on it.
For a member variable, the scope is the lifetime of the object.
struct S {
std::string str_;
char* p_;
};
int main() { // scope
{ // scope
S s;
} // end scope -> s.~S() -> str_.~string()
}
Note in the above that nothing special happens to p_: it's a pointer which is a simple scalar type, so the code does nothing automatic to it.
So in your list class the only thing you have to worry about is your next member: you need to decide whether it is an "owning" pointer or not. If it is an "owning" pointer then you must call delete on the object in your destructor.
Alternatively, you can leverage 'RAII' (resource aquisition is initialization) and use an object to wrap the pointer and provide a destructor that will invoke delete for you:
{ // scope
std::unique_ptr<Node> ptr = std::make_unique<Node>(args);
} // end scope -> ptr.~unique_ptr() -> delete -> ~Node()
unique_ptr is a purely owning pointer, the other alternative might be shared_ptr which uses ref-counting so that the underlying object is only deleted when you don't have any remaining shared_ptrs to the object.
You would consider your next pointer to be a non-owning pointer if, say, you have kept the actual addresses of the Nodes somewhere else:
std::vector<Node> nodes;
populate(nodes);
list.insert(&nodes[0]);
list.insert(&nodes[1]);
// ...
in the above case the vector owns the nodes and you definitely should not be calling delete in the Node destructor, because the Nodes aren't yours to delete.
list.insert(new Node(0));
list.insert(new Node(1));
here, the list/Nodes are the only things that have pointers to the nodes, so in this use case we need Node::~Node to call delete or we have a leak.
Basically you should just
delete next
and that's all you should do:
The string and vector objects have their own destructors, and since this object is being destructed, theirs will be called.
Deleting a null pointer is not a problem, so you don't even have to check for that.
If next is not a null pointer, it will keep on calling the destructors of the next nodes, on and on, as needed.
Just delete it and that's all, then.
Your class destructor will be called (it is empty), then the member objects destructors are called.
If member is not an object, no destructor is called.
In your example:
- List *next: pointer on List: no destructor called
- string sName: string object: destructor called
- vector<char> cvStuff: vector object: destructor called
Good news: you have nothing to do. Destructor declaration is not even useful here.
If you delete next in your destructor, then deleting an item will delete all other items of your list: not very useful.
(and your List object should rather be called Node). The List is the chained result of all your nodes, held by the first node you created.

C++ Setting Pointer Equal to shared_ptr

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!

How to add an element into the vector of pointers?

I have this:
std::vector <BinaryTree*> children;
where BinaryTree is a class. How can I add an element into this vector?
I tried children.push_back(X) where X is an instance of the class but it gives me this error:
cannot convert parameter 1 from 'BinaryTree' to 'BinaryTree *&&'
Just use the push_back() and pass a pointer to an instance of BinaryTree:
std::vector <BinaryTree*> children;
BinaryTree* pTree = new BinaryTree();
children.push_back(pTree);
...
delete pTree;
In order to avoid manual memory management, if you need reference semantics, use smart pointers instead of raw pointers:
#include <memory> // For std::shared_ptr
std::vector <std::shared_ptr<BinaryTree>> children;
std::shared_ptr<BinaryTree> pTree = std::make_shared<BinaryTree>();
children.push_back(pTree);
...
// No need to delete pTree
The std::shared_ptr<> class template is part of the C++11 Standard Library. In C++03, you could use the (almost) equivalent boost::shared_ptr<>:
#include <boost/shared_ptr.hpp> // For std::shared_ptr
std::vector <boost::shared_ptr<BinaryTree>> children;
boost::shared_ptr<BinaryTree> pTree = boost::make_shared<BinaryTree>();
children.push_back(pTree);
...
// No need to delete pTree
Finally, if you do not need reference semantics at all and want to treat your binary trees as values instead, you can even consider defining a std::vector<BinaryTree>:
std::vector<BinaryTree> children;
BinaryTree tree;
children.push_back(tree);
Omit the asterisk * from the template argument:
std::vector<BinaryTree> children;
You want children to hold the data, without manual/dynamic memory allocation as in new BinaryTree.
It really depends on who is supposed to own the pointers. In the simplest case, where the vector doesn't own them, then you pass the address of a BinaryTree object.
BinaryTree b = ...;
children.push_back(&b);
But you have to be sure b lives at least as long as children does.
If the vector owns the pointers, then you should probably store smart pointers to avoid having to deal with memory managemen:
std::vector<std::unique_ptr<BinaryTree>> children;
children.push_back(std::unique_ptr<BinaryTree>(new BinaryTree(args)));
If you don't know what all this "ownership" business means, then you are most likely better off with a plain vector of objects:
std::vector<BinaryTree> children;
std::vector<SomeObject*> objectVector;
objectVector.push_back(new SomeObject());
Is how I do it.
children.push_back(&X);
This will work but bear in mind that once your object leaves scope, its deleter will be called and you will be left with an invalid pointer.
children.push_back(&X);
Pass the address as if you were using it as a pointer. But the problem then is if that instance goes out of scope, so better to do this
BinaryTree* X = new BinaryTree;
children.push_back(X);
This will ensure that X never goes out of scope, but then you have to manually delete it when you're finished with it.
The vector contains pointers to objects of type BinaryTree. You need
BinaryTree bt;
children.push_back( &bt );
But you must ensure that the lifetime of the bt object at least matches that of the vector.
You may want this instead
children.push_back( new BinaryTree );
But in this case you must call delete on the pointer contained in the vector to prevent a memory leak.
As evident, neither option is easy to manage. An easy change is to make your container store the elements by value.
std::vector<BinaryTree> children;
BinaryTree bt;
children.push_back( bt );
If you must store pointers, use a smart pointer to hold them instead.
std::vector<std::unique_ptr<BinaryTree>> children;
children.push_back( new BinaryTree );
Now you don't need to worry about deleting the objects before emptying the vector.
You have vector of pointers:
std::vector <BinaryTree*> children;
so the proper way of adding elements is:
BinaryTree* child = new BinaryTree();
children.push_back(child);
just be careful while doing something like this:
{
BinaryTree child;
children.push_back(&child);
}
because lifetime of such an element might be shorter than lifetime of the vector and you might end up trying to access an element that no longer exists (dangling pointer) which produces undefined behavior. Also don't forget to delete these elements when done with it.
But it's always good to consider using vector of objects first (i.e.std::vector<BinaryTree>) since that would take care of that ugly memory management for you.

Is it a memory leak to push_back a pointer into a vector of pointers?

In my class, I have a member variable std::vector<node*> children
Does the following class member function create a memory leak?
//adds a child node
{
node* child = new node("blah","blah","blah");
child->Set_Parent(this);
children.push_back(child); //<- Is this ok?
}
The vector makes a copy of the pointer and I have two pointers to the same memory,
and then the original pointer goes out of scope, right?
This may be simple and obvious, but I would just like to confirm my assumption.
thanks
It's not a leak ... yet. However, if the vector goes out of scope, or you erase, pop_back or do something else that removes elements from the vector, without first deleteing the element that you're removing you'll have a leak on your hands.
The right way to do this is to change from using a vector<node *> to vector<unique_ptr<node>>. Your code will change to
//adds a child node
{
node* child = new node("blah","blah","blah");
child->Set_Parent(this);
children.push_back(std::unique_ptr<node>(child));
}
Or use boost::ptr_vector<node> if you can use Boost.
It's only a memory leak if you forget to deallocate the children node when the class containing the vector's destructor is called.
It's not a memory leak. You still have a pointer in the vector and you will be able to free the memory when needed.
When the vector goes out of scope, it's destructor doesn't destroy the pointed-to object. It destroys the pointer -- which does nothing.
Your code created that object via new. Your code is responsible for deleting that object. If you don't do so, you have a leak. If you do so to early, i.e., before removing the pointer from the vector, you have even bigger problems.
Assuming children is a class member you would just simply delete all the items in the vector on the class deconstructor.
struct Foo{};
class Bar
{
public:
Bar(){};
~Bar()
{
for( vector<Foo*>::iterator it = children.begin(); it != children.end(); ++it )
{
SAFE_DELETE( (*it) ); //use your own macro/template or use delete if you don't have one
delete (*it);
(*it) = NULL;
}
}
vector<Foo*>children;
}
Foo* p = new Foo();
children.push_back( p );
If you used a vector<Foo>child instead, every push_back on the vector would create a copy of the original object to be stored, but since you're using pointers, in this case allocated on the heap by new no object copy is created, the pointer that points to a long-life term object is simply stored, meaning yes, you have to delete it later.

why am i getting this runtime exception when using shared_ptr?

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 &copy); //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;