Output iterator on a set: assign and increment iterator - c++

There are many questions about output iterator and sets but none of them address this particular topic.
I writing a function to deserialize a sequence of objects to a container. I wish this function be as general as possible, so container can be either a set or a vector.
I'm thinking on receiving an OutputIterator as argument where to put each new object as they are deserialized. I'm not sure what to expect when writing to the iterator if the container is a set.
To be brief, let say the containers in this example hold int instead of pointers to objects, returned one by one by getIntFromInput().
void deserializeToContainer(OutputIterator oit){
while(moreInputAvailable()){
*oit = getIntFromInput();
oit++;
}
}
void deserializeToVector(vector<int> &vectorContainer){
deserializeToContainer(vectorContainer.back_inserter());
}
void deserializeToSet(set<int> &setContainer){
deserializeToContainer(setContainer.end());
}
Since set hasn't a back_inserter, and elements aren't stored in the order they are inserted, I wonder what to expect about *oit assignment and oit increment when the container is a set, like in deserializeToSet
Thank you very much.

You can use a std::insert_iterator (probably with std::inserter)
void deserializeToSet(set<int> &setContainer){
deserializeToContainer(std::inserter(setContainer, setContainer.end()));
}

Related

Can I get a container object from an iterator?

std::vector<int> vec={1,2,3};
std::vector<int>::iterator it = vec.begin();
if(vec == get_vec_from_it(it)){
puts('sucesss');
}
std::vector<int> get_vec_from_it(std::vector<int>::iterator it){
/*?*/
}
How should I write get_vec_from_it function in the above example?
The basic idea is that iterators abstract away where the elements come from, there might not even be a container. Afaik there is a single type of iterator that "knows" its container and that is std::back_insert_iterator, though thats an exception. The container member is only protected so there is even a way to get the container from a std::back_insert_iterator, but thats not how it is meant to be used.
You can adance the iterator to get the next element, but you wouldn't know where to stop, because at some point you'll reach the end of the vector and there is no way to identify it. If you pass begin and end you can create a copy of the original vector:
std::vector<int> get_vec_from_it(std::vector<int>::iterator begin ,std::vector<int>::iterator end){
return {begin,end};
}
Though, thats just a different way to copy the vector and you need to know both begin and end.
I made a function that returns the iterator that points to the node but I couldn't write the stop condition in a for statement. So I wonder if the stop condition can be written like it!=get_vec_from_it(it).end()
Functions that work on a range of elements typically take a pair of iterators, first and last, to know where to stop (alternatively a first iterator and number of elements can be used). Your idea of using it!=get_vec_from_it(it).end() is overcomplicating the issue. Just pass vec.end() to the function and use that: it != end.
No.
You can create a vector from a pair of iterators, or an iterator and number of elements. Example:
std::vector<int>
get_vec_from_its(std::vector<int>::iterator first, std::vector<int>::iterator last){
return std::vector<int>(first, last);
}
// ...
if(vec == get_vec_from_it(vec.begin(), vec.end())){
The function is of course so trivial that I would recommend instead to use the constructor directly.

a pushBack() function, as opposite to popFront()

Can I use popFront() and then eventually push back what was poped? The number of calls to popFront() might be more than one (but not much greater than it, say < 10, if does matter). This is also the number of calls which the imaginary pushBack() function will be called too.
for example:
string s = "Hello, World!";
int n = 5;
foreach(i; 0 .. n) {
// do something with s.front
s.popFront();
}
if(some_condition) {
foreach(i; 0 .. n) {
s.pushBack();
}
}
writeln(s); // should output "Hello, World!" since number of poped is same as pushed back.
I think popFront() does use .ptr but I'm not sure if it in D does makes any difference and can help anyway to reach my goal easily (i.e, in D's way and not write my own with a Circular buffer or so).
A completely different approach to reach it is very welcome too.
A range is either generative (e.g. if it's a list of random numbers), or it's a view into a container. In neither case does it make sense to push anything onto it. As you call popFront, you're iterating through the list and shrinking your view of the container. If you think of a range being like two C++ iterators for a moment, and you have something like
struct IterRange(T)
{
#property bool empty() { return iter == end; }
#property T front() { return *iter; }
void popFront() { ++iter; }
private Iterator iter;
private Iterator end;
}
then it will be easier to understand. If you called popFront, it would move the iterator forward by one, thereby changing which element you're looking at, but you can't add elements in front of it. That would require doing something like an insertion on the container itself, and maybe the iterator or range could be used to tell the container where you want an alement inserted, but the iterator or range can't do that itself. The same goes if you have a generative range like
struct IncRange(T)
{
#property bool empty() { value == T.max; }
#property T front() { return value; }
void popFront() { ++value; }
private T value;
}
It keeps incrementing the value, and there is no container backing it. So, it doesn't even have anywhere that you could push a value onto.
Arrays are a little bit funny because they're ranges but they're also containers (sort of). They have range semantics when popping elements off of them or slicing them, but they don't own their own memory, and once you append to them, you can get a completely different chunk of memory with the same values. So, it is sort of a range that you can add and remove elements from - but you can't do it using the range API. So, you could do something like
str = newChar ~ str;
but that's not terribly efficient. You could make it more efficient by creating a new array at the target size and then filling in its elements rather than concatenating repeatedly, but regardless, pushing something on the the front of an array is not a particularly idiomatic or efficient thing to be doing.
Now, if what you're looking to do is just reset the range so that it once again refers to the elements that were popped off rather than really push elements onto it - that is, open up the window again so that it shows what it showed before - that's a bit different. It's still not supported by the range API at all (you can never unpop anything that was popped off). However, if the range that you're dealing with is a forward range (and arrays are), then you can save the range before you pop off the elements and then use that to restore the previous state. e.g.
string s = "Hello, World!";
int n = 5;
auto saved = s.save;
foreach(i; 0 .. n)
s.popFront();
if(some_condition)
s = saved;
So, you have to explicitly store the previous state yourself in order to restore it instead of having something like unpopFront, but having the range store that itself (as would be required for unpopFront) would be very inefficient in most cases (much is it might work in the iterator case if the range kept track of where the beginning of the container was).
No, there is no standard way to "unpop" a range or a string.
If you were to pass a slice of a string to a function:
fun(s[5..10]);
You'd expect that that function would only be able to see those 5 characters. If there was a way to "unpop" the slice, the function would be able to see the entire string.
Now, D is a system programming language, so expanding a slice is possible using pointer arithmetic and GC queries. But there is nothing in the standard library to do this for you.

c++: popping an element by key out of an std::map

I'm interested in removing an element with a specific key out of a map and use this element.
Something that will look like:
itr = MyMap.pop(wantedKey);
//Now MyMap is missing the element which has the key 'wantedKey'.
//Do something with this element through 'itr'.
Is there an stl map method for doing this?
EDIT
Following carleeto's response, I want to clarify: What I need is the element being removed from the map and the program being able to use it afterwards, it could be the element itself as a pair, not necessarily an iterator.
There are two options: use it in-place then remove it, or move it to a local variable, remove the entry, then use it.
// use-remove
auto i = MyMap.find(wantedKey);
if (i != MyMap.end()) {
// use-remove
use(i->second);
MyMap.erase(i);
// or
// move-remove-use
auto x = std::move(i->second);
MyMap.erase(i);
use(x);
} else {
// Not found
}
Not that I know of, but you can use std::map::find to get an iterator and then call std::map::erase with said iterator as an argument when you're done.
From your variable naming, I think you might be confusing concepts here.
itr = MyMap.pop(wantedKey);
//Do something with this element through 'itr'.
Iterators only point to elements in containers. Therefore, if you had received an iterator through a function called pop (even if it existed), the iterator would reference not the element you popped, but probably the one after or before it, like std::vector::erase. This is because the purpose of an iterator is to iterate over the elements in a container. Therefore, if an element is not in the container, you cannot get an iterator to it. However, even if you used the iterator returned by the erase function, it would not reference you would be expecting it to.
So you can erase an element from the map, like so many have pointed out, by searching for it, getting the ierator to it and then calling erase with that iterator. but you cannot get an iterator that points to element you have erased. Hope this clears things up.
UPDATE: If all you want is to access the element and use it, then all you need to do use std::map::find to get an iterator and std::map::erase to remove the item from the map, once you have finished using the iterator. The reason is that even if you have stored a copy of the iterator for future use, once you call erase, it will be invalidated. To be able to access it after you have erased it, depending on scope, you will probably need to copy it.
Finally, what you want to do is a very common task - look up a map based on a key and perform an operation on the associated element. It's quite likely that you have a list of keys to go through. You should also look up functors, std::for_each and std::transform. I realise this is not operating on the element after you have removed it, but I thought I would add it in, seeing as how its a related operation. For example: You could move all elements that match a list of keys into another container (say, a vector, and then use the above to operate on them).
Probably what you want to do is
itr = MyMap.find('thing in a string');
to find the iterator and then use it,
MyMap.erase(itr)
And then erase it.
Pop() belongs to the stack datastructure. To access an element of a map, use the [] operator (http://www.cplusplus.com/reference/map/map/operator%5B%5D/), to remove it from the map use (http://www.cplusplus.com/reference/map/map/erase/).
itr = MyMap.find(wantedKey);
if(itr != MyMap.end()) {
use( itr->second );
MyMap.erase(itr);
}
your.uncle = bob;
Using C++'s std::map<T, U>::find():
map.erase(map.find(key));
The way I did it is below. In my case the map stores std::shared_ptr values, making the copy cheap(ish), and the object ownership transferral clear.
auto it = MyMap.find( wantedkey );
if ( it == MyMap.end() ) throw runtime_error("not found");
auto ret = it->second; // make copy of shared_ptr
MyMap.erase(it);
return ret;
The caller gets a shared_ptr with a reference count of at least one (from the copy). Note the function must return the shared_ptr by value, etc.

Is this the correct way to access objects inside a list?

EDIT: TLDR? Here's a summary:
The requirement is for an essentially infinitely (or arbitrarily) long container. So list sounds like a good idea, because it will fit the objects in whatever memory space is available.
However vectors are much faster/efficient at access, but might not be able to fit in memory if we don't have a long sequential strip.
Vector of pointers was suggested to reduce memory usage, but the problem remains if there are a gigabyte of pointers and I have 4GB of ram, it might just not fit!
Solution: A list of vectors might be the way to go. Each item in the list could be a vector with 1000 pointers to items which we want to be able to access. A class could handle this functionality.
** Original Question:**
As a wise man once said: "With pointers, if it works once, that doesn't guarantee you are doing it correctly."
I have a class:
class A;
And class A is inside a std::list:
std::list<A> list_of_A;
To access items inside it I am using:
std::list<A>::iterator iter = list_of_A.begin();
std::advance(iter, <an_unsigned_int>);
return *iter;
This seems to be working, but is return *iter the correct thing to be doing? I should mention the last 3 lines are inside a function which returns a const A&.
I looked for an answer on stackoverflow, but couldn't find a duplicate of this question, which surprises me.
List > Vector because I will be swapping things in and out of the list.
Yes; you will return a reference inside the list if your function returns A& or A const& and a copy if your function returns A.
However, if you are doing this regularly, why not use a std::vector? They have random access iterators and are almost always more efficient than a std::list, unless the objects are large and you have a large number of them. std::list are very cache-inefficient.
This is good as long as you have not advanced to (or past) end().
const A& stuff(std::list<A>& list_of_A, int index)
{
assert(index <= list_of_A.size()); // Protect against UB
// of advancing past end.
std::list<A>::iterator iter = list_of_A.begin();
std::advance(iter, index);
if (iter == list_of_A.end())
{ throw std::runtime_error("Failed"); // Not allowed to de-reference end()
}
return *iter;
}

Returning STL lists as argument

I have a function that reads lines from a log file, converts these lines to a certain class and returns a STL list of instances of this class.
How should I declare this function so that the whole list is NOT copied when attributing it to the caller?
Without loss of generality, assume:
list<Request> requests = log_manipulator.getAsRequestList();
How should I declare getAsRequestList()? Should I return a reference to a list or just return a list?
This is a serious issue because in this particular assignment the lists will contain circa 1.5M elements, and thus a mistake like that can screw up memory usage.
Returning a reference is not advisable, and returning the list object would cause copying. Best would be to change the method's signature to accept and populate a list reference:
list<Request> requests;
log_manipulator.getRequestListByRef(requests);
with void getRequestListByRef(list<Request>&) as the method's signature.
You have two easy options:
A return parameter
void getAsRequestList(list<Request>& requests);
...
list<Request> requests;
log_manipulator.getAsRequestList(requests);
An output iterator
template <class OutputIterator>
void getAsRequestList(OutputIterator dest);
...
list<Request> requests;
log_manipulator.getAsRequestList(
insert_iterator< list<Request> >(requests, requests.begin()) );
See also: How do I return hundreds of values from a C++ function?
You might be able to get away with returning a simple list - search for "Return Value Optimization" for details. Simply, the compiler is allowed to generate code that bypasses the costly copy constructor.
Only after trying this and not being satisfied with the results would I recommend the "populate" versions suggested in the other answers. It's uglier.
Of course, the caveat is that RVO is not guaranteed to happen.
Return a auto_ptr to the list:
auto_ptr<list<Request> > getAsRequestList()
{
auto_ptr<list<Request> > list = new list<Request>();
// populate list
return list;
}
Return a local variable as a reference is a funny thing in C++,
list<Request>& requests = log_manipulator.getAsRequestList();
it is compiler dependent so works in one machine but not the other.
your best bet is to declare your getAsRequestList() this way
void getAsRequestList(list<Request>& requests)
{
// populate results in requests
}
or new your requests on heap with in getAsRequestList() and return a pointer
A pointer to a list or you can rewrite it as:
list<request> requests;
log_manipulator.populate_list(&requests);
Pass as in/out parameter by reference is definately my choice.
But just to give an alternative you could pass an iterator. Normally you would have to pre-size the container so that assignment by the iterator goes into a pre-allocated slot but the STL also has a back inserting iterator that you could use.
#include <iostream>
#include <iterator>
#include <list>
template<typename T>
void FillMyContainer(T inserter)
{
for(int loop=0;loop < 10;++loop)
{
(*inserter) = loop;
++inserter;
}
}
int main()
{
/*
* Example of back_inserter in use.
*/
std::list<int> data;
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(data));
/*
* Using back_inserter in the context of the question
*/
std::list<int> fill;
FillMyContainer(std::back_inserter(fill));
}
So the question now becomes why does log_manipulator not have methods to return an iterator rather than a list. Then your underlying implementation does not need to rely on a specific container type?
Declare is as
void getAsRequestList(list<Request>* requests);
And call it as
list<Request> requests;
log_manipulator.getAsRequestList(&requests);
Since you have mentioned about memory usage, Have you considering treating log_manipulator as 'iterator' or treat log_manipulator as container and write an iteator (e.g. log_iter) which iterates over it? Such that iterator operator++ will result in reading and parsing the next line from the log file and operator * will return a current 'request object'. As long as the iterator corresponds to STL iterator semantics, you can use any STL algorithms on it.
For example, You can then easily convert it to a vector using
std::vector<Request> reqvector;
std::copy(log_manipulator.begin(), log_manipulator.end(), std::back_inserter(reqvector))
(assuming begin(),end() function return a 'log_iter')
Check Writing Your Own Iterators article from Dr. Dobb's journal