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.
Related
Suppose I'm writing a project in a modern version of C++ (say 11 or 14) and use STL in that project. At a certain moment, I need to program a specific data structure that can be built using STL containers. The DS is encapsulated in a class (am I right that encapsulating the DS in a class is the only correct way to code it in C++?), thus I need to provide some sort of interface to provide read and/or write access to the data. Which leads us to the question:
Should I use (1a) iterators or (1b) simple "indices" (i.e. numbers of a certain type) for that? The DS that I'm working on right now is pretty much linear, but then when the elements are removed, of course simple integer indices are going to get invalidated. That's about the only argument against this approach that I can imagine.
Which approach is more idiomatic? What are the objective technical arguments for and against each one?
Also, when I choose to use iterators for my custom DS, should I (2a) public-ly typedef the iterators of the container that is used internally or (2b) create my own iterator from scratch? In the open libraries such as Boost, I've seen custom iterators being written from scratch. On the other hand, I feel I'm not able to write a proper iterator yet (i.e. one that is as detailed and complex as the ones in STL and/or Boost).
Edit as per #πάντα ῥεῖ request:
I've asked myself this question with a few DS in a few projects while studying at the Uni, but here's the last occurrence that made me come here and ask.
The DS is meant to represent a triangle array, or vertex array, or whatever one might call it. Point is, there are two arrays or lists, one storing the vertex coordinates, and another one storing triplets of indices from the first array, thus representing triangles. (This has been coded a gazillion times already, yet I want to write it on my own, once, for the purpose of learning.) Obviously, the two arrays should stay in sync, hence the encapsulation. The set of operations is meant to include adding (maybe also removing) a vertex, adding and removing a triangle (a vertex triplet) using the vertex data from the same array. How I see it is that the client adds vertices, writes down the indices/iterators, and then issues a call to add a triangle based on those indices/iterators, which in turn returns another index/iterator to the resulting triangle.
I don't see why you couldn't get both, if this makes sense for your container.
std::vector has iterators and the at/operator[] methods to provide access with indexes.
The API of your container depends on the operations you want to make available to your clients.
Is the container iterable, i.e. is it possible to iterate over each elements? Then, you should provide an iterator.
Does it make sense to randomly access elements in your container, knowing their address? Then you can also provide the at(size_t)/operator[size_t] methods.
Does it make sense to randomly access elements in your container,
knowing a special "key"? The you should probably provide the at(key_type)/operator[key_type] methods.
As for your question regarding custom iterators or reuse of existing iterators:
If your container is basically a wrapper that adds some insertion/removal logic to an existing container, I think it is fine to publicly typedef the existing iterator, as a custom iterator may miss some features of the the existing iterator, may contain bugs, and will not add any significant feature over the existing iterator.
On the other hand, if you iterate in a non-standard fashion (for instance, I implemented once a recursive_unordered_map that accepted a parent recursive_unordered_map at construction and would iterate both on its own unordered_map and on its parent's (and its parent's parent's...). I had to implement a custom iterator for this.
Which approach is more idiomatic?
Using iterators is definitely the way to go. Functions in <algorithm> don't work with indices. They work with iterators. If you want your container to be enabled for use by the functions in <algorithm>, using iterators is the only way to go.
In general, it is recommended that the class offers its own iterator. Under the hood, it could be an index or a STL iterator (preferred). But, as long as external clients and public APIs are concerned, they only deal with the iterator offered by the class.
Example 1
class Dictionary {
private:
typedef std::unordered_map<string, string> DictType;
public:
typedef DictType::iterator DictionaryIterator;
};
Example 2
class Sequence {
private:
typedef std::vector<string> SeqType;
public:
struct SeqIterator {
size_t index;
SeqIterator operator++();
string operator*();
};
};
If the clients are operating solely on SeqIterator, then the above can later be modified to
class Sequence {
private:
typedef std::deque<string> SeqType;
public:
typedef SeqType::iterator SeqIterator;
};
without the clients getting affected.
Say for example, an element is referenced from multiple maps, e.g. a map name to element, a map address to element and a map age to element. Now one looks up the element for example via name, and now wishes to delete it from all three maps?
Several solutions come to mind:
1) The most straight forward. Look up the element in the name to element map, then search both other maps to find the element in those, then remove the element entry in all three.
2) Store weak pointers in all three maps. Store a shared pointer somewhere, at best maybe even in the element itself. After finding the element in one map, delete the element. When trying to access the element from the other maps and realizing the weak pointers can't be converted to shared pointers, remove the entry.
3) Use intrusive maps. This has the advantage that one does not need to search the remaining maps to find the element in those. However, as the object is stored in several maps, the element itself can't be made intrusive - rather the element might need to have a member implementing the hooks.
4) Others?
Is there a very clean nice solution to this? I have been bumping into this problem a few times...
A few thoughts. Solution 1 is typically the one that ends up being implemented naturally as a project grows. If the element itself has the key information of the other maps, and other containers are maps, this is probably quite acceptable. However, if the keys are missing, or if the container is e.g. a list, it can become very slow. Solution 2 depends on the implementation of weak pointers, and might also end up being quite slow. Solution 3 seems best, but maybe somewhat complicated?
boost::multi_index is designed specially for such case.
Sounds like you haven't decided what is managing the lifetime of the object - that comes first. Once you know that then use the observer pattern. When the object is to be destroyed, the objected magaing its lifetime notifies all the objects that wrap the maps holding the pointers, then destroys the object.
The observers can either implement a common interface like this:
class ObjectLifetimeMgr
{
public:
CauseObjDeletion()
{
/.. notify all observers ../
}
private:
list<IObserver*> observers;
};
class IObserver
{
public:
virtual void ObjectDestroyed( Obj* );
};
class ConcreteObserver
{
public:
void ObjectDestroyed( Obj* )
{
/.. delete Obj from map ../
}
};
Or to do a really lovely job you could implement a c++ delegate, this frees the observers from a common base class and simply allows them to register a callback using a member method
Never found anything to replace solution 1. I ended up with shared_pointers and delete flags in a delete function (e.g. DeleteFromMaps(bool map1, bool map2, bool map3)) in the object. The call from eg map2 then becomes e.g.
it->DeleteFromMaps(true,false,true);
erase(it);
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.
I am trying to use a map container to hold Shapes and match those shapes to an ID number.
Until now, I have always used STL containers to hold and memory-manage my objects. So I would use containers of these sorts:
std::map<int, Square> squares;
std::map<int, Triangle> triangles;
std::map<int, Circle> circles;
But I want to have a single map to hold "Shapes", and this is an abstract base class of Square, Triangle and Circle. So to achieve this, I would still store the realisable derived class objects in their own maps, and then have another map:
std::map<int, Shape*> shapes;
to store pointers to the objects stored in the other maps.
This seems very messy though, and I'd rather store all the objects in a single polymorphic map that owns and memory-manages the contained objects.
After reading a little about Boost's ptr_map I expected this was the solution. But it seems that the base class needs to be realisable as while trying to use:
boost::ptr_map<int,Shape> shapes;
I get the error: "error: cannot allocate an object of abstract type 'Shape'"
Must I make the base class realisable? That would be a bit of a hack so I'd rather do this properly, if there is such a way.
My next best guess about how to do this is to use a container such as:
std::map<int, boost::shared_ptr<Shape> > shapes;
This seems like such a straightforward aim, but since I'm having such difficulty with it I suspect I'm trying to do something I shouldn't. So any advice about where I might be going wrong is greatly appreciated.
Thanks.
ptr_map<int, Shape> seems like the way to go, and works even with abstract base type (see an example here). I guess the error you obtain comes from the use of operator[]. Indeed, like in std::map, the operator[] returns a default-constructed value if the key was not already in the map. In this case, it can't construct the value since Shape is abstract, hence the compiler error.
So you can use ptr_map but not the indexing operator. When inserting, use insert, when looking up a key, use find.
Your base class does not need to be realisable. See the example here: http://www.boost.org/doc/libs/1_49_0/libs/ptr_container/doc/tutorial.html#associative-containers
The animal there does have abstract functions! In fact, this is one of the primary uses for ptr containers. Your error is probably caused elsewhere and you need to post more code.
Also:
This seems very messy though, and I'd rather store all the objects in a single polymorphic map that owns and memory-manages the contained objects.
I don't think it is. It can actually be beneficial to never "lose" the type of the actual object, in case you need that later. For example, if you wanted to do something for all Triangles, but not all other shapes, this will come in handy.
The disadvantage is of course that you need to keep all the maps in sync, but this is very easy to solve: Stick those 4 maps (and preferably no other data members!) into the private section of a class and implement 3 overloads for the different types and always insert them into the strongly typed "owning" map and into the map with polymorphic pointers. I will be very easy to keep them in sync behind a small class interface. Just don't try to do it as an unstructured part of something bigger, or the code will start to look messy.
I'm new to c++ but have set my mind on a specific task that needs me to enable adding a specific chunk of code to be execute whenever any list item is attempted to be changed or read.
The resulting list should behave and look as much as as possible to std::list except for this small exception that would enable me to execute a specific tasks whenever this list is about to be read/written to.
From what i have found out so far, all i could think of is deriving a class from list::iterator and overloading it's operator* and operator= to implement these specific tasks.
Then i should derive a class from std::list and make it use my new iterator type by overloading begin() and end() methods. Or is there a better way of making it use a custom iterator?
That would handle the iterator access but I can see lists can even return pointers to it's members. I guess there is nothing i can do about them and will have to remove this feature from my new list class.
I would appreciate your oppinion on this subject.
Deriving from std::list is almost certainly not the answer. The collections in stl are simply not meant to be derived from and doing so will cause you problems down the road.
The classic example of why is the destructor problem. The destructors in stl collections are not virtual. This will break any logic you place in your derived class destructor if an object is deleted via a reference to the std::list. For example
std::list* pList = new YourNewListClass();
delet pList; // runs std::list::~list()
You'd also need to override much more than the methods on the iterator. It would require changing every method which can possibly mutate the collection.
A more stable approach would be to implement your own std::list style class which follows the standard stl container behavior. You could then include use this list in the places you wanted events without running into the problems with deriving from std::list.
Look at the way that std::deque implements it's functionality as an adaptor of another standard collection. This is the way to go -- use composition not inheritance and wrap the underlying collection to provide your new facilities. For bonus points template your implementation on the underlying collection. For many uses a std::vector will outperform a std::list and your additions should be able to work equally well with whichever of these the user chooses.
First things first..NEVER derive a class from STL containers as they are not meant to be derived. For starters their destructor is not virtual.
The easiest way would be contain a std::list in your own class and providing list like interfaces. In these list like interfaces you can provide any additional tasks you want to perform before/updating the list.
Also, take a look at this design pattern: Decorator
Take a look at boost::transform_iterator<>. It seems to be close to what you're looking for. It calls a functor whenever the operator*() function of the transform_iterator<> is called. The intended use is to transform the object the iterators points to, but there's nothing that says the functor can't do something else and simply return the original value of the pointed to object.
Even if it's not quite what you want, it will probably provide ideas to how you might approach your problem.