class T
{
unordered_map<string, int> table;
...
void updateA(const unordered_map<string, int>::iterator& iter)
{
iter->second = 100;
}
void updateB(unordered_map<string, int>::iterator iter)
{
iter->second = 100;
}
};
Question> Which function is better(i.e. updateA or updateB)? If you have a better one, please propose.
Thank you
1) First, to answer the question in the title, is it necessary to pass iterators by (const) reference: No. An iterator acts as a proxy for the data item in the container, regardless of whether or not the iterator itself is a copy of or a reference to another iterator. Also in the case when the iterator gets invalidated by some operation performed on the container, whether you maintain it by copy or reference will not make a difference.
2) Second, which of the two options is better.
I'd pass the iterator by copy (i.e. your second option).
The rule of thumb is: Pass by reference if you either want to modify the original variable passed to the function, or if the object you pass is large and copying it involves a major effort.
Neither is the case here: Iterators are small, lightweight objects, and given that you suggested a const-reference, it is also clear that you don't want to make a modification to it that you want reflected in the variable passed to the function.
3) As a third option, I'd like you to consider adding const to your second option:
void updateC(const unordered_map<string,int>::iterator iter)
{
iter->second = 100;
}
This ensures you won't accidentally re-assign iter inside the function, but still allows you to modify the original container item referred to by iter. It also may give the compiler the opportunity for certain optimizations (although in a simple situation like the one in your question, these optimizations might be applied anway).
Related
Do I understand correctly, that since std::map's node-handle insertion takes r-value:
insert_return_type std::map::insert(node_type&& nh),
the node-handle cannot be used (to change value) after insertion?
std::map<...> m;
// Wrong:
m.insert(nh);
nh.value() = new_value;
// Right:
auto it = m.insert(nh);
it->second = new_value;
The object at nh will be copied out of, but the returned iterator will point to the new copy that exists inside the map.
The first example is indeed wrong, since nh can't be used for anything other than destruction after being moved from.
That's generally true, even without the r-value form: the map creates a value that lives inside its own data structure, and is a copy of the one being passed in to insert. For the regular (const &) form, you understand that changing the original will not affect the map!
I'm trying to do strange things again.
Okay, here's the general idea. I want a std::list (and vector and so on) that actually own the objects they contain. I want to move the values into it, and access them by reference.
Example using a list of unique_ptr:
using namespace std;
list<unique_ptr<T>> items; // T is whatever type
items.push_back(make_unique(...));
items.push_back(make_unique(...));
for ( unique_ptr<T> item : items )
item.dosomething();
With me so far? Good. Now, let's do it with stack semantics and rvalue references. We can't just use a list<T&&> for obvious reasons, so we'd have to make a new class:
using namespace std;
owninglist<T> items;
items.push_back(T());
items.push_back(T());
for ( T& item : items )
item.dosomething();
Of course, I might want an owningstack or owningvector as well, so ideally we want it to be templated:
owning<std::list<T>> items;
The owning<U<T>> class should inherit whatever push_back() and pop_front() etc functions the underlying collection has. Presumably to achieve that, I'd need to code a generic base class, and derive explicit specialisations for the collections that have unusual functions:
template<typename T> owning<std::queue<T>> : owningbase<T> {
void push_front() { ... }
}
I'm getting stuck on the iterators. The begin() and end() functions should return an iterator that works the same as the underlying collection's iterator would, except with an operator*() that returns the item by lvalue reference instead of by value.
We'd need some way to transfer ownership of an item out of the list again. Perhaps the iterator could have an operator~ that returns the item as an rvalue, deletes the item from the list, and invalidates the iterator?
Of course, all this is assuming the underlying std::list (or whatever) can be convinced to take an rvalue. If push_back() copies the value in as an lvalue, then none of this is going to work. Would I be better off coding a container from scratch? If I did, is there some way to put the majority of the code for list, queue, stack and vector into a single base class, to save rewriting pretty much the same class four times over?
Perhaps I could introduce an intermediate class, some kind of wrapper? So owned<list<T>> could inherit from list<refwrapper<T>> or something? I know boost has a reference_wrapper, but I'm not sure it fits this scenario.
If you want to avoid copy elements around you can use std::move.
So if you have a std::list you can populate it with values by moving them in:
SomeBigObject sbo;
std::list<SomeBigObject> list;
list.push_back(SomeBigObject()); // SomeBigObject() is a rvalue and so it is moved
list.push_back(std::move(sbo)); // sbo may not be a rvalue so you have to move it
// For construction you can also use std::list::emplace
list.emplace(list.end()); // construct the value directly at the end of the list
For accessing them you can simply use the ranged based loop:
for(auto& i :list)
...
If you want to move them out of the container you can also use std::move.
The object is moved out of the container but the remains will still be in the container,
so you have to erase them:
for(auto it = list.begin; it != lsit.end();)
{
// the value of *it is moved into obj;
// an empty value of "SomeBigObject" will remain so erase it from the list
SomeBigObject obj = std::move(*it);
it = list.erase(it);
// do something with "obj"
...
}
I'm trying to understand what const_iterator means. I have the following example code:
void CustomerService::RefreshCustomers()
{
for(std::vector<Customer*>::const_iterator it = customers_.begin();
it != customers_.end() ; it ++)
{
(*it)->Refresh();
}
}
Refresh() is a method in the Customer class and it is not defined as const. At first thought I thought const_iterator was supposed to disallow modification to the elements of the container. However, this code compiles without complaint. Is this because there's an extra level of indirection going on? What exactly does const_iterator do/mean?
UPDATE
And in a situation like this, is it best practice to use const_iterator?
A const_iterator over a vector<Customer*> will give you a Customer * const not a Customer const*. So you cannot actually change the value being iterated (a pointer), but you sure can change the object pointed to by it. Basically all it says in your case is that you can't do this:
*it = ..something..;
You're not modifying the contents of the container. The contents of the container are just pointers. However, you can freely modify whatever the pointers point to.
If you didn't want to be able to modify what the pointers point to, you'd need a vector<const Customer*>.
const_iterator is not about whether you can modify the container or not, but about whether you can modify the objects in the container or not. In your case the container contains pointers, and you cannot modify the pointers themselves (any more than you could modify integers...) You can still make call to non-const Refresh() behind a pointer from the collection, because that call does not change the pointer itself.
Difference between const_iterator and iterator is important [only] when your container contains e.g. class instances, not pointers to them, but the instances themselves, for example in a container
list < pair < int , int > >
If 'it' is a const_iterator into this list, you can't do
it->first = 5
but if it is iterator (not const_iterator), that works.
In the following example a std::list stores objects of type Resource (by value, not pointing to). The Resource class does not provide a less than comparison nor equality operator. What is a good way to remove an object by identity (aka memory address). Can i avoid O(n) somehow? Is std::list the right container?
// Definition of the container
std::list<Resource> resources;
// Code
Resource *closedResource = resourceFromList();
for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); ++it)
{
if (closedResource == &*it)
{
resources.erase(it);
break;
}
}
Edit: Assume that the Resource class implements move semantic. Furthermore the Resource reregisters itself for any "movement" by a kind of Selector (cp. epoll or java.nio.Selector) for event notifications.
You're storing Resource copies in the container, so later finding an element by address doesn't make much sense.
What you can do is save list::iterators since list has the property that iterators are not invalidated by any operation expect explicitly erasing that iterator (or clearing the entire list).
Edit: Sorry, never mind this answer -- if you are certain only to be removing at most one element, then your loop is fine.
Never mind whether comparing by memory address is sensible, but to use list::erase in a loop you have to write it a little differently to avoid incrementing an invalidated iterator:
for (std::list<Resource>::iterator it = resources.begin(); it != resources.end(); )
{
if (want_to_erase) it = resources.erase(it); // advances to the next position
else ++it;
}
If you have no other requirements than look-up by address, you could always just make a std::set or std::unordered_set of elements and implement Resource::operator<() as pointer comparison.
Either way, there are certain conditions on types for them to be eligible as STL container members; as was asked in the comments, do those conditions apply to your Resource class? Otherwise you could just make a container of std::shared_ptr<Resource> and use its inbuilt comparators, and for example make an std::unordered_set<std::shared_ptr<Resource>>.
"Is std::list the right container?"
I doubt it. If this class does not provide a comparison operator you can still provide one yourself
struct resourcecomparation {
const bool operator() (const Resource &l, const Resource &r) const;
}resourcecomparator;
and then you can use, for instance, an std::set<resource, resourcecomparator>.
This is a pretty straightforward architectural question, however it's been niggling at me for ages.
The whole point of using a list, for me anyway, is that it's O(1) insert/remove.
The only way to have an O(1) removal is to have an iterator for erase().
The only way to get an iterator is to keep hold of it from the initial insert() or to find it by iteration.
So, what to pass around; an Iterator or a pointer?
It would seem that if it's important to have fast removal, such as some sort of large list which is changing very frequently, you should pass around an iterator, and if you're not worried about the time to find the item in the list, then pass around the pointer.
Here is a typical cut-down example:
In this example we have some type called Foo. Foo is likely to be a base class pointer, but it's not here for simplicity.
Then we have FooManger, which holds a list of shared_ptr, FooPtr . The manager is responsible for the lifetime of the object once it's been passed to it.
Now, what to return from addFoo()?
If I return a FooPtr then I can never remove it from the list in O(1), because I will have to find it in the list.
If I return a std::list::iterator, FooPtrListIterator, then anywhere I need to remove the FooPtr I can, just by dereferencing the iterator.
In this example I have a contrived example of a Foo which can kill itself under some circumstance, Foo::killWhenConditionMet().
Imagine some Foo that has a timer which is ticking down to 0, at which point it needs to ask the manager to delete itself. The trouble is that 'this' is a naked Foo*, so the only way to delete itself, is to call FooManager::eraseFoo() with a raw pointer. Now the manager has to search for the object pointer to get an iterator so it can be erased from the list, and destroyed.
The only way around that is to store the iterator in the object. i.e Foo has a FooPtrListIterator as a member variable.
struct Foo;
typedef boost::shared_ptr<Foo> FooPtr;
typedef std::list<FooPtr> FooPtrList;
typedef FooPtrList::iterator FooPtrListIterator;
struct FooManager
{
FooPtrList l;
FooPtrListIterator addFoo(Foo *foo) {
return l.insert(l.begin(), FooPtr(foo));
}
void eraseFoo(FooPtrListIterator foo) {
l.erase(foo);
}
void eraseFoo(Foo *foo) {
for (FooPtrListIterator it=l.begin(), ite=l.end(); it!=ite; ++it) {
if ((*it).get()==foo){
eraseFoo(it);
return;
}
}
assert("foo not found!");
}
};
FooManager g_fm;
struct Foo
{
int _v;
Foo(int v):_v(v) {
}
~Foo() {
printf("~Foo %d\n", _v);
}
void print() {
printf("%d\n", _v);
}
void killWhenConditionMet() {
// Do something that will eventually kill this object, like a timer
g_fm.eraseFoo(this);
}
};
void printList(FooPtrList &l)
{
printf("-\n");
for (FooPtrListIterator it=l.begin(), ite=l.end(); it!=ite; ++it) {
(*it)->print();
}
}
void test2()
{
FooPtrListIterator it1=g_fm.addFoo(new Foo(1));
printList(g_fm.l);
FooPtrListIterator it2=g_fm.addFoo(new Foo(2));
printList(g_fm.l);
FooPtrListIterator it3=g_fm.addFoo(new Foo(3));
printList(g_fm.l);
(*it2)->killWhenConditionMet();
printList(g_fm.l);
}
So, the questions I have are:
1. If an object needs to delete itself, or have some other system delete it, in O(1), do I have to store an iterator to object, inside the object? If so, are there any gotchas to do with iterators becoming invalid due other container iterations?
Is there simply another way to do this?
As a side question, does anyone know why and of the 'push*' stl container operations don't return the resultant iterator, meaning one has to resort to 'insert*'.
Please, no answers that say "don't pre-optimise", it drives me nuts. ;) This is an architectural question.
C++ standard in its [list.modifiers] section says that any list insertion operation "does not affect the validity of iterators and references", and any removal operation "invalidates only the iterators and references to the erased elements". So keeping iterators around would be safe.
Keeping iterators inside the objects also seems sane. Especially if you don't call them iterators, but rather name like FooManagerHandlers, which are processed by removal function in an opaque way. Indeed, you do not store "iterators", you store "representatives" of objects in an organized structure. These representatives are used to define a position of an object inside that structure. This is a separate, quite a high-level concept, and there's nothing illogical in implementing it.
However, the point of using lists is not just O(1) insert/remove, but also keeping elements in an order. If you don't need any order, then you would probably find hash tables more useful.
The one problem I see with storing the iterator in the object is that you must be careful of deleting the object from some other iterator, as your objects destructor does not know where it was destroyed from, so you can end up with an invalid iterator in the destructor.
The reason that push* does not return an iterator is that it is the inverse of pop*, allowing you to treat your container as a stack, queue, or deque.