deleting shared pointers by using an ordered map - c++

I am currently coding a shell in c++ whose file-system is implemented in main memory. I am trying to store the pointers to inodes which is either plain field or directory in a ordered map in the following manner:
using inode_ptr = shared_ptr<inode>;
map<string,inode_ptr> dirents;
So basically the string will map either a file or a directory. For the rm "remove function", what I am trying to do is to deallocate what the pointer points to and the pointer itself by using delete:
void directory::remove (const string& filename) {
DEBUGF ('i', filename);
delete dirents[filename];
dirents.erase(filename);
}
So basically, I deallocate the object and the pointer, and then delete it from the map; however, I am getting a compiler error which states the following:
error: type ‘std::map<std::basic_string<char>, std::shared_ptr<inode> >::mapped_type {aka class std::shared_ptr<inode>}’ argument given to ‘delete’, expected pointer
delete dirents[filename];
what am I doing wrong?
I also think that somehow the idea is wrong because the deletion of a directory has to be recursive. Eliminating what the ptr points to doesn't get rid of the whole chain; however, I don't know if that's true.

Your problem lies in the try of deleting a std::shared_ptr<T>. You do not perfom a delete on that object. The destructor of it does what you really want for you. Simply call erase on your map at specified key and, while you erase that object, the destructor will automatically delete the content if there are no remaining shared_ptrs referencing this allocation (very good point user4581301 ).*
Your function would look like that:
void directory::remove (const string& filename) {
DEBUGF ('i', filename);
dirents.erase(filename); // erasing that object makes it call a delete on content
}
EDIT: Just some quick tip - if your map provides the only way of accessing those pointers, consider using std::unique_ptr<T> instead of std::shared_ptr<T>.
*if you really want to perform a delete there, I would highly encourage you to switch to unique pointers. Usage of shared ones indicates that there might be some other pointers pointing to the memory you want to deallocate. If that's the case - your original approach was not correct. Either use std::unique_ptr here or don't assume you could delete the content of the ptrs.

Related

_block_type_is_valid(phead- nblockuse) when erasing data from a vector of shared_ptr

It's my first time posting so I do apologize if I've messed up in anyway or made anything more difficult than it should be.
Here's my issue:
I'm trying to erase data from a vector of boost::shared_ptr nodes, nodes being a class.
In one part of my code, erasing an element from a vector known as openList works fine.
In another part of my code, erasing an element from a vector known as movingObjectsList, doesn't want to work. It gives prompts me with _block_type_is_valid(phead- nblockuse).
I've tried clear(), popback() and erase() and all of them cause the same problem. I can add what I like to movingObjectsList without any errors and swap the data it holds with other vectors, but I'm unable to delete any of the data.
I think I've ruled out it being an issue with the node destructor because I have the same issue when I use Ints instead of nodes, and also the openList is able to erase elements.
This is how it's declared in the header.
vector<boost::shared_ptr <node>> movingObjectsList;
This is the relevant code in the cpp
grid::grid()
{
movingObjectsList = vector<boost::shared_ptr<node>>();
}
void grid::createGrid(){
boost::shared_ptr<node> movingObject = boost::shared_ptr<node> (&nodes[8][8]);
movingObjectsList.push_back(movingObject);
}
void grid::movingObjects()
{
movingObjectsList.erase(movingObjectsList.begin());
}
This is the simplest form I've cut it down to, only concerning movingObjectsList.
Without the erase function, it works fine.
As answer I reiterate what I said in my comment: When the reference counter of a shared_ptr reaches zero the contained pointer will be deleted. This means that it will basically be the same as delete &nodes[8][8]. As it's not allocated with new, you will experience undefined behavior.
OK, mistake in what a shared pointer does.
A Shared pointer takes full ownership of a pointer. When that pointer goes out of scope, it'll delete that pointer.
You are inializsing the nodes as an node [8][]. Your pointer is an address in this 2D array! When you need to call delete (which'll get called when your shared_ptr goes out of scope i.e. whenever you remove elements from the vector), you are essentially calling delete nodes[i][j], which you'd expect to barf.
Just use references in this case (Node&), which will be perfectly valid and work just fine.

Exception safety C++ shared pointer

I try to implement a JSON framework in C++ and want to make use of polymorphic concepts. I have a class JSONNode which is kind of container that stores other JSONNode objects itself and so on. I am doing this with pointers and dynamic allocation. For exception safety I do not want to use new/delete but go with boost shared pointer. A basic scenario for adding an element (a further json object) to a json object looks like this:
typedef boost::shared_ptr<JSONNode> JSONNodePtr;
void JSONNode::Add(JSONNodePtr nodePtr, const std::string& name)
{
this->elements[name] = nodePtr; // store in STL std::map
}
// create and add json object
JSONNodePtr obj(new JSONNode());
JSONNodePtr element(new JSONNode());
obj->Add(element, "firstElement");
For easier use I would rather do it without explicit allocation of element and put the creation of the shared pointer into the class method Add:
void JSONNode::Add(JSONNode* node, const std::string& name)
{
JSONNodePtr nodePtr(node);
this->elements[name] = nodePtr;
}
// create and add json object
...
obj->Add(new JSONNode, "firstElement");
But is that still exception safe? I guess not because the creation of the shared pointer is not immediately done with the allocation of the JSONNode*. What do you think? Or are there other more common ways to implement this?
But is that still exception safe?
No. If the construction of the string to pass as the other argument to Add throws, then the dynamic object may be leaked. It is unspecified which argument is created first.
The original code ensures that the dynamic object is assigned to a smart pointer before anything else happens: the only thing that could fail is the creation of the smart pointer itself, in which case it will delete the object.
Or are there other more common ways to implement this?
It's generally a better idea to use the make_shared function template, rather than using new yourself. Not only does it guarantee exception safety by never exposing a naked pointer, it also makes more efficient use of memory by creating the controlled object and the shared reference count in a single block of memory.
obj->Add(boost::make_shared<JSONNode>(), "firstElement"); // or std:: in C++11

C++ Safe returning a pointer to an iterater after map insert?

So I have some C++ classes that use a map and key class for a sort of data structure. In my insert method I use the typical map.insert. I want this function to return a pointer so I can modify some values (not the one used for comparison) inside the element inserted. So I was wondering if this is safe to this..
template<typename T>
NodeT<T> * TreeT<T>::
MakeNode(PointT point)
{
NodeT<T> * prNode = new NodeT<T>;
//set the contents for the node
prNode->SetNode(point, m_dTolerance);
//Create the key class using the
VectorKey key(point, m_dTolerance);
//Store the key,node as a pair for easy access
return_val = m_tree.insert( pair<VectorKey, NodeT<T> >(key, *prNode) );
if (return_val.second == false)
//if return_val.second is false it wasnt inserted
prNode = NULL;
else
//it was inserted, get a pointer to node
prNode = &(return_val.first->second); //is this safe if I plan to use it later?
return prNode;
}
I seemed to learn the hard way that my original pointer (the one I created with new), was pointing to the wrong element after the insert. Can anyone tell me why that is? So I used the return_val iterator to get the right pointer. I kinda dont want to return an iterator but if its safer then I do...
Thanks!
You seems to have troubles in your code with pointers and values. First you allocate an object on a heap ( with new Node )
Then you use a copy of that object to sore within your map.
PS. And then you loose original object forever as do not free memory which leads to memory leak.
In your case - it is invalid because you return pointer to object which can be deleted at any time ( for example next time you add something to your map and map decides to reallocate it's tree, so it will copy objects to different places ).
Storing pointers as map values prevents this. The only thing you need to remember to clear them up when removing object from map and when removing map itself.
The easy way to handle that would be using smart pointers (boost::shared_ptr for example ) or smart map class (boost::ptr_map for example ).
To fix that - use pointers everywhere ( store a pointer as a map value ).
This way - you will be able to return pointer from this function and it will be valid.
So just turn your map to map*> and this should fix most of your problems.
Do not forger to delete objects when erasing them from the map.
This code sample is interesting because contains a several things wrongs or to avoid.
Implementation
The most important things are been said (mainly by Bogolt):
You are leaking memory, because allocate NodeT<T> from the heap and never free it again, since map will allocate a copy of the object, not the pointer. Indeed, you specify as parameter *prNode, not prNode.
You use the heap to allocate the object (will be copied into the map), but you assume you always allocate the object. Despite it will be the very most probably case, that is not alway true: new operator would be return null or throw a bad_alloc exception. The code does not handle it.
Anyway, you use the heap when is not really needed. (And you see the problems are you intriducing because that). You can just create the object in the stack and then insert into the map, avoiding the previous problems and typing less code.
Design
The function returns a pointer to the element in the map. Depending the program, is possible this is safe. But what happens if the code reference the pointer when the object is removed from the map? Better, if you are returning pointer, do not return a raw pointer. Use smart pointer (shared_ptr in this case) instead. Using shared_ptr you will have not problems with the object life.
Other reason to use smart pointers: because the insertion into the map imply a copy of the element, you are imposing a requirement to NodeT<T>: it has to be copy constructible. May be this requirement is not important for performance, but may be in other circumstances copying the object have drawbacks. If you use smart pointer (or boost::ptr_map), the object will be created just once and is not copied.
Style
Just some suggestion, but not too important:
instead type pair<VectorKey, NodeT<T> >(key, *prNode), type make_pair(key, *prNode). The code is more compact and clearer typing less.
Well I'd say that depends on is your map alive longer than anything that could use (and store) the pointer.
If yes, (ie, it's in some sort of singleton), you could go with it, but not very safe anyway since any code could delete the pointer.
The best option is to store boost::shared_ptr (or std:: since c++11) instead of raw pointers in your mapn and return only a weak_ptr after insertion.
That way, you're sure no other code can delete your pointer as long as the map holds it, and that no one can use a pointer that has been erased from the map.

C++ basic pointer question

I have some shared pointer shared_ptr<T> pointer1(new T(1));.
Now, in some other part of code I have an explicit copy of pointer2 (guess it would be stored in a std::map or some other container). Let's say that copy was done like map.insert(make_pair(key1, pointer1));.
I am using that second copy only to precache some data and this means that if the main pointer is already invalid, there is no need to store the second pointer. What should I do in this case?
Is there any way to force the memory deallocation for the second pointer if I know that pointer1 became invalid in some other part of my code?
Or should I take the ugly way - from time to time check my map for pointers which have ptr.unique() set to true and destruct them?
Maybe some alternatives / advices?
Edit - plain code sample
std::map<int, shared_ptr<int> > map;
{
shared_ptr<int> pointer1(new int(5));
map.insert(std::make_pair(0, pointer1));
}
Is there any way / trick to make map contain <0, shared_ptr[NULL]> instead of <0, shared_ptr[5]> after these operations happen?
Thanks
It sounds like this is a task for weak_ptr:
http://www.boost.org/doc/libs/1_40_0/libs/smart_ptr/weak_ptr.htm
Try putting them in your table instead of a shared_ptr.
I am using that second copy only to precache some data and this means that if the main pointer is already invalid, there is no need to store the second pointer. What should I do in this case?
You should look at boost::weak_ptr
If the associated shared_ptr has been reset then the weak_ptr knows about it.
Is there any way to force the memory deallocation for the second pointer if I know that pointer1 became invalid in some other part of my code?
Don't think so.
But if you use weak pointer this will not be required.

linked list memory management

How could I free up a linked list that contains dynamically allocated objects?
I try to use list<class*> lists, but then I could not use the insert() function to insert object to the list. Does anyone know what is the cause?
std::list<boost::shared_ptr<YourType> > will automatically call YourType::~YourType on each (smart) pointer in the list, when the list is deleted. And if you erase one list element, it will call YourType::~YourType for that one element. You can still call list.insert(new YourType)
Link: www.boost.org
how could I free up linked list that contain dynamically allocated object?
Walk the list, deleting the contained object for each link, or better in some cases, write a link dtor that deletes the contained object.
I try to use list lists, but then I could not use insert()function to insert object to the list. Does anyone know what is the cause?
Not without seeing your code.
Traverse the list from the beginning to end, and delete one by one.
The solution used by the STL is to have the container own the objects it contains. In this scenario each node would be responsible for deallocating it's object when it's destructor is called. You're still responsible for deallocating the copy of the object you pass in.
Edit
If you're attempting to use the stl List and encountering an error, it might be the case that the object you're trying to place inside does not implement a copy constructor. This can happen if you try to stick things other than pointers into the list. If you're comfortable with pointers you might consider storing them in your containers instead of the objects themselves. This will require that you call 'delete' yourself on the pointer when you're done with it. This is typically done by calling 'delete' on the pointer contained in a node when you remove it or by walking the list when you're done with it and calling 'delete' on the contents of each node.
You will have to iterate the list and delete the dynamically allocated objects, before clearing the list.
When using containers of newed
pointers, please remember to delete
the pointers before the container is
destroyed.
About problem using insert() : I am not very sure what is the problem you are facing. From the explanation, I assume, you are trying to insert objects of Class into list where as the list contains the pointer to Class. Could you please elaborate the problem with insert?
Pseudo code for deleting the dynamically allocated objects:
version 1: Simple
list<Class*>::const_iterator iter = m_ClassList.begin();
list<Class*>::const_iterator endIter = m_ClassList.end();
for(;iter!= endIter ; ++iter)
{
delete *iter;
}
ClassList.clear();
version 2: A better version using for_each
struct DeleteClassObject
{
//Functor
template<typename T>
void operator()(const T* ptr) const
{
delete ptr;
}
}
//loops through list and deletes the dynamically allocated objects using
//functor DeleteClassObject
for_each( m_ClassList.begin(), m_ClassList.end(), DeleteClassObject ());
DeleteClassObject.clear()
You could use ptr_list from Boost
http://www.boost.org/doc/libs/1_38_0/libs/ptr_container/doc/ptr_list.html
EDIT: THIS IS WRONG, SORRY
If you're using std::list then there's a clear function to delete all objects you put in.
std::list test;
test.clear();
Oh, and .clear() also invokes the destructors.
To use the insert function of such lists you need to specify the position via an iterator.
test.insert(test.end(), 5);
But there's more than 1 insert function, here you can find more details
EDIT
Could somebody leave a comment when downvoting?
Start your project in language/environment, which having an automatic memory management (Garbage collection). Then things like that will be the least which you care about. It will save your time to put your efforts into something else.