Remove item from a list using its pointer - c++

I have a pointer p (not an iterator) to an item in a list. Can I then use p to delete (erase) the item from the list? Something like:
mylist.erase(p);
So far I have only been able to do this by iterating through the list until I reach an item at the location p, and then using the erase method, which seems very inefficient.

Nope, you'll have to use an iterator. I don't get why getting the pointer is easier than getting an iterator though...

A std::list is not associative so there's no way you can use a pointer as a key to simply delete a specific element directly.
The fact that you find yourself in this situation points rather to questionable design since you're correct that the only way to remove the item from the collection as it stands is by iterating over it completely (i.e. linear complexity)
The following may be worth considering:
If possible, you could change the list to a std::multiset (assuming there are duplicate items) which will make direct access more efficient.
If the design allows, change the item that you're pointing to to incorporate a 'deleted' flag (or use a template to provide this) allowing you to avoid deleting the object from the collection but quickly mark it as deleted. Drawback is that all your software will have to change to accommodate this convention.
If this is the only bit of linear searching and the collection is not big (<20 items say.) For the sake of expediency, just do the linear search as you've suggested but leave a big comment in the code indicating how you "completely get" how inefficient this is. You may find that this does not become a tangible issue in any case for a while, if ever.
I'm guessing that 3 is probably your best option. :)

This is not what I advice to do, but just to answer the question:
Read only if you are ready to go into forbidden world of undefined behavior and non-portability:
There is non-portable way to make an iterator from T* pointer to an element in a list<T>. You need to look into your std library list header file. For Gnu g++ it includes stl_list.h where std::list definition is. Most typically std::list<T> consists of nodes similar to this:
template <class T>
struct Node {
T item;
Node* prev;
Node* next;
};
Having pointer to Node<T>::item you can by using offsetof calculate this node pointer. Be aware that this Node template could be the private part of std::list so you must hack this - let say by defining identical struct template with different name. std::list<>::iterator is just wrapper over this node.

It cannot be done.
I have a similar problem in that I'm using epoll_wait and processing a list of events. The events structure only contains a union, of which the most obvious type to use is void * to indicate which data is relevant (including the file descriptor) that was found.
It seems really silly that std::list will not allow you to remove an element via a pointer since there is obviously a next and previous pointer.
I'm considering going back to using the Linux kernel LIST macros instead to get around this. The problem with too much abstraction is that you have to give up on interoperability and communication with lower level apis.

Related

How does a linked list know when its element has been removed from the list and adjust?

I made a singly linked list and am creating an iterator for it but I am running into a problem when the element currently pointed to gets removed from the list. I have a class called list and within it, I have a nested class called iter. Currently iter's only field is a *currentNode pointer (it gets passed in a node in the constructor).
So how do I handle when the element that it is pointing to gets deleted. My first thought was that I should try to handle that in my list's remove() functions but I don't think it is possible to / don't know how to tell from the list's point of view whether the current element is being pointed to by the iterator (the iterator's currentNode pointer seems to not be in the scope of the class based on the compiler's errors). My second thought was to try to handle it from the iterator itself, but I can't figure out how to even begin to go about that.
I'm sorry if the answer is really simple. I couldn't find the answer anywhere online which makes me think that it might be but I just can't figure out how to handle this for the life of me. Thank you!
The list does not need to know anything about the iterator or its content. When the iterator removes its current node from the list, the iterator is invalidated. Even iterators in most standard STL container behave that same way. If you look at std::list, for instance, its erase(iterator) method returns a new iterator that represents the next node in the list following the node that was removed. You can do the same in your own remove() method. Otherwise, remove() would have to update the iterator to point at a different node, but that tends to go against how iterators typically operate.
You have 2 options.
If you dereference an iterator to an object that doesn't exist it is undefined behavior. The standard library does it and it is accepted. Also it is easy to implement since you don't need to handle that case.
Keep a std::shared_ptr to the element. That way the value does not get deleted as long as the iterator exists. You have to pay a performance penalty for doing this even if you do not use the feature. Additionally it can be perceived as hiding a bug.

sorting a list - the best way possible

I have a list
std::list<Selector> _selectorList;
I do parse on something and I get a smart pointer and a priority associated with the smart pointer. I implemented a structure to hold these two parameters like shown below.
struct Selector
{
int priority;
SmartPointer *selector;
}
There will be n number of parsing which will be done, as a result n number of struct instances will be pushed back into the list. At the end I am supposed to sort the list according to the decreasing order of priority variable in the structure. Currently, I plan to do this.
_selectorList.sort();
Is there any better approach than this, provided that I must use a list (only and nothing else) to store the smart pointers returned by parsing?
Like larsman told you using a pointer to a SmartPointer is highly probably wrong. Since smart pointers are used to avoid memory leaks, the reference counter is updated on object copy or assignment, so a SmartPointer * is probably useless.
For what concerne a better approach, you could reuse std::list::sort instead of reimplementing your own sort operation. The only things to do is let your Selector implement comparison operator in order to be able to sort your list.
Have a look here.

use map in place of vector

I am extending an already existing C++ code.
One of the class members is of type vector of another class objects:
class Road
{
....
vector<Link*> links; //Link is just another class
}
The other modules use this class and its member through a lot of sequence iterators.
Now, while extending the code, I need to add a member to Link class called linkID, and use this linkID to find/access my "Link" objects.
Problem:
I am not going to search for a Link object(using LinkID) in the vector by iterating through the millions of items, just to find a specific Link object. The best solution is "map"! right?
....
map<linkID,*link> links
....
lnk=links[linkID]
.........
But the problem is that i cannot modify the current source code except very minor modifications lik adding linkID etc.
So my obvious question is:
is it possible to use map in place of vector(any how).
In the other words, I want to create a map, fill it up, and later treat it as a vector. possible?
Thank you for your comments
The best solution is "map"! right?
Yes, sounds like the map is the simplest solution to your problem. But instead of using operator[], I'd use find and insert methods.
Initially, you can change the code to use the map of this type std::map< unsigned int, link* >, because that is the most similar to a vector< link* >. Then you can easily switch to std::map< LinkId, link* >.
I think what you might be able to do is make an augmented data structure: a vectormap which allows you to have keyed access to the items by linkID and which also supports the operations of std::vector. The [] operator of this object could be overloaded so that links[3] gives you positional access to the vector and links[linkID] looks up a link ID in the map. Things like push_back can be supported, if the code needs them: push_back would have to push the element into the vector, and then also do a map[item->linkID] = item to enter it into the map. You probably get the picture.
Disguising a map as vector is not possible as such.
In theory, you could try to implement a new class that is derived from vector (i.e. uses std::vector as base class). Internally it could use a map, and to the outside it would have the interface of a vector (and it would be accepted as a replacement for the vector because it is derived of it).
In practice you might encounter a number of problems, though. You would obviously inherit the internal data structures of the vector, too, so you would have to ignore them in your implementation, i.e. leave them empty. Deriving from STL classes (except basic_ ones) is also against recommended practice and possibly risky, as #Als points out in the comment below.
If there is a chance to avoid this by rewriting a larger portion of the existing code, you should do that. But if unavoidable, using inheritance might work.
I did this many moons ago for the rail network. The base classes were link and node. The actual rail and eventually routes were based on top of these. IIRC I used std::list to contain links and nodes and used vectors of vectors for containing the actual tracks.
The proper solution, if linkID is a member of Link, would be std::set<Link*, OrderByLinkID>. The OrderByLinkID predicate would take two Link* and return true iff the first has a smaller linkID member.
The result is that the std::set still contains Link*, and you can iterate over them just like std::vector. In comparison, with std::map you'd end up iterating over std::pair<Link*, LinkID> which is a much bigger change.

Dynamically allocated list in C++

I made a cute generic (i.e. template) List class to handle lists in C++. The reason for that is that I found the std::list class terribly ugly for everyday use and since I constantly use lists, I needed a new one. The major improvement is that with my class, I can use [] to get items from it. Also, still to be implemented is an IComparer system to sort things.
I'm using this List class in OBJLoader, my class that loads Wavefront .obj files and converts them to meshes. OBJLoader contains lists of pointers to the following "types": 3D positions, 3D normals, uv texture coordinates, vertices, faces and meshes. The vertices list has objects that must be linked to some objects in all of the 3D positions, 3D normals and uv texture coordinates lists. Faces link to vertices and meshes link to faces. So they are all inter-connected.
For the sake of simplicity, let's consider that, in some context, there are just two lists of pointers: List<Person*> and List<Place*>. Person class contains, among others, the field List<Place*> placesVisited and the Place class contains the field List<Person*> peopleThatVisited. So we have the structure:
class Person
{
...
public:
Place* placeVisited;
...
};
class Place
{
...
public:
List<People*> peopleThatVisited;
};
Now we have the following code:
Person* psn1 = new Person();
Person* psn2 = new Person();
Place* plc1 = new Place();
Place* plc2 = new Place();
Place* plc2 = new Place();
// make some links between them here:
psn1->placesVisited.Add(plc1, plc2);
psn2->placesVisited.Add(plc2, plc3);
// add the links to the places as well
plc1->peopleThatVisited.Add(psn1);
plc2->peopleThatVisited.Add(psn1, psn2);
plc3->peopleThatVisited.Add(plc3);
// to make things worse:
List<Person*> allThePeopleAvailable;
allThePeopleAvailable.Add(psn1);
allThePeopleAvailable.Add(psn2);
List<Place*> allThePlacesAvailable;
allThePlacesAvailable.Add(plc1);
allThePlacesAvailable.Add(plc2);
allThePlacesAvailable.Add(plc3);
All done. What happens when we reach }? All the dtors are called and the program crashes because it tries to delete things two or more times.
The dtor of my list looks like this:
~List(void)
{
cursor = begin;
cursorPos = 0;
while(cursorPos < capacity - 1)
{
cursor = cursor->next;
cursorPos++;
delete cursor->prev;
}
delete cursor;
}
where Elem is:
struct Elem
{
public:
Elem* prev;
T value;
Elem* next;
};
and T is the generic List type.
Which brings us back to the question: What ways are there to safely delete my List classes? The elements inside may or may not be pointers and, if they are pointers, I would like to be able, when I delete my List, to specify whether I want to delete the elements inside or just the Elem wrappers around them.
Smart pointers could be an answer, but that would mean that I can't have a List<bubuType*>, but just List<smart_pointer_to_bubuType>. This could be ok, but again: declaring a List<bubuType*> would cause no error or warning and in some cases the smart pointers would cause some problems in the implementation: for example, I might want to declare a List<PSTR> for some WinAPI returns. I think getting those PSTR inside smart pointers would be an ugly job. Thus, the solution I'm looking for I think should be somehow related to the deallocation system of the List template.
Any ideas?
Without even looking at your code, I say: scrap it!
C++ has a list class template that's about as efficient as it gets, well-known to all C++ programmers, and comes bug-free with your compiler.
Learn to use the STL.1 Coming from other OO languages, the STL might seem strange, but there's an underlying reason for its strangeness, an alien beauty combining abstraction and performance - something considered impossible before Stepanov came and thought up the STL.
Rest assured that you are not the only one struggling with understanding the STL. When it came upon us, we all struggled to grasp its concepts, to learn its particularities, to understand how it ticks. The STL is a strange beast, but then it manages to combine two goals everybody thought could never be combined, so it's allowed to seem unfamiliar at first.
I bet writing your own linked list class used to be the second most popular indoor sport of C++ programmers - right after writing your own string class. Those of us who had been programming C++ 15 years ago nowadays enjoy ripping out those bug-ridden, inefficient, strange, and unknown string, list, and dictionary classes rotting in old code, and replacing it with something that is very efficient, well-known, and bug-free. Starting your own list class (other than for educational purposes) has to be one of the worst heresies.
If you program in C++, get used to one of the mightiest tools in its box as soon as possible.
1Note that the term "STL" names that part of the C++ standard library that stems from Stepanov's library (plus things like std::string which got an STL interface attached as an afterthought), not the whole standard library.
The best answer is that you must think on the lifetime of each one of the objects, and the responsibility of managing that lifetime.
In particular, in a relation from people and the sites they have visited, most probably neither of them should be naturally made responsible for the lifetime of the others: people can live independently from the sites that they have visited, and places exists regardless of whether they have been visited. This seems to hint that the lifetime of both people and sites is unrelated to the others, and that the pointers held are not related to resource management, but are rather references (not in the C++ sense).
Once you know who is responsible for managing the resource, that should be the code that should delete (or better hold the resource in a container or suitable smart pointer if it needs to be dynamically allocated), and you must ensure that the deletion does not happen before the other objects that refer to the same elements finish with them.
If at the end of the day, in your design ownership is not clear, you can fall back to using shared_ptr (either boost or std) being careful not to create circular dependencies that would produce memory leaks. Again to use the shared_ptrs correctly you have to go back and think, think on the lifetime of the objects...
Always, always use smart pointers if you are responsible for deallocating that memory. Do not ever use raw pointers unless you know that you're not responsible for deleting that memory. For WinAPI returns, wrap them into smart pointers. Of course, a list of raw pointers is not an error, because you may wish to have a list of objects whose memory you do not own. But avoiding smart pointers is most assuredly not a solution to any problem, because they're a completely essential tool.
And just use the Standard list. That's what it's for.
In the lines:
// make some links between them here:
psn1->placesVisited.Add(plc1, plc2);
psn2->placesVisited.Add(plc2, plc3);
// add the links to the places as well
plc1->peopleThatVisited.Add(psn1);
plc2->peopleThatVisited.Add(psn1, psn2);
plc3->peopleThatVisited.Add(plc3);
You have instances on the heap that contain pointers to each others. Not only one, but adding the same Place pointer to more than one person will also cause the problem (deleting more than one time the same object in memory).
Telling you to learn STL or to use shared_ptr (Boost) can be a good advice, however, as David Rodríguez said, you need to think of the lifetime of the objects. In other words, you need to redesign this scenario so that the objects do not contain pointers to each other.
Example: Is it really necessary to use pointers? - in this case, and if you require STL lists or vectors, you need to use shared_ptr, but again, if the objects make reference to each other, not even the best shared_ptr implementation will make it.
If this relationship between places and persons is required, design a class or use a container that will carry the references to each other instead of having the persons and places point at each other. Like a many-to-many table in a RDBMS. Then you will have a class/container that will take care of deleting the pointers at the end of the process. This way, no relations between Places and Persons will exist, only in the container.
Regards, J. Rivero
Without looking the exact code of the Add function, and the destructor of your list, it's hard to pin point the problem.
However, as said in the comments, the main problem with this code is that you don't use std::list or std::vector. There are proven efficient implementations, which fit what you need.
First of all, I would certainly use the STL (standard template library), but, I see that you are learning C++, so as an exercise it can be nice to write such a thing as a List template.
First of all, you should never expose data members (e.g. placeVisited and peopleThatVisited). This is a golden rule in object oriented programming. You should use getter and setter methods for that.
Regarding the problem around double deletion: the only solution is having a wrapper class around your pointers, that keeps track of outstanding references. Have a look at the boost::shared_ptr. (Boost is another magnificent well-crafted C++ library).
The program crashes because delete deallocates the memory of the pointer it is given it isn't removing the items from you list. You have the same pointer in at least two lists, so delete is getting called on the same block of memory multiple times this causes the crash.
First, smart pointers are not the answer here. All they will do is
guarantee that the objects never get deleted (since a double linked list
contains cycles, by definition).
Second, there's no way you can pass an argument to the destructor
telling it to delete contained pointers: this would have to be done
either via the list's type, one of its template arguments, partial
specialization or an argument to the constructor. (The latter would
probably require partial specialization as well, to avoid trying to
delete a non-pointer.)
Finally, the way to not delete an object twice is to not call delete on
it twice. I'm not quite sure what you thing is happening in your
destructor, but you never change cursor, so every time through, you're
deleting the same two elements. You probably need something more along
the lines of:
while ( cursor not at end ) {
Elem* next = cursor->next;
delete cursor;
cursor = next;
}
--
James Kanze
And you could easily implement [] around a normal list:
template <class Type>
class mystdlist : public std::list<Type> {
public:
Type& operator[](int index) {
list<Type>::iterator iter = this.begin();
for ( int i = 0; i < index; i++ ) {
iter++;
}
return *iter;
}
};
Why you would want to do this is strange, IMHO. If you want O(1) access, use a vector.

Changing a Container while using Visitor

I implemented the Visitor pattern in C++ using a STL-like iterator for storing the Visitor's current position in the container. Now I would like to change the container while I iterate over it, and I'm especially interested in deleting items from the container, even the one I'm currently visiting.
Now obviously this will invalidate the Visitors internal iterator, because it was pointing to exactly this item. Currently, I store a list of all iterators in the container and update them, as soon as anything is added to or removed from the list. So in a way this is similar to the Observer pattern applied to the iterator (as Observer) and the list (as Observable).
Alternatively I considered having the visitor() methods return some hint to the Visitor about what happend to the current item and how to proceed iterating, but that doesn't sound like such a good idea either, because the visit() implementation shouldn't really care about finding the next item.
So, my question is: What's the best way to keep a visitor working, even when items are added to the container or removed from it.
Regards,
Florian
Update: There's one visitor running over the container, but inside of the visit() method any number of additional iterators might be used on the same container. I want the visitor to continue with the remaining items in the container, even after we returned from a call to visit() in which any one of the items in the container got deleted.
When mutating the container during traversal, iterators are hazardous, at best. It is safest to use an index and walk backwards.
I think your (first) implementation is pretty good if there are not so many iterators and delete operations. If this would be the case I would use a mark and sweep like algorithm like Eddy recommended. Also, I think the latter is easier and thus less error prone. Don't forget to skip nodes which are marked for deletion.
On the other hand, if there are cases besides 'delete' where your iterators need to be updated, stick to your current implementation.
In these cases, if copying my container is not expensive, I just copy it and iterate on the copy. The original container holds objects by shared_ptr while the copy just holds weak_ptr.