Vector<tuple>, make_tuple<int, ignore, float> - c++

I create a vector of tuples:
std::vector<std::tuple<int*, bool, int*>> *DataStucture;
Next I want to iterate over a data set to get only the first element of each tuple.
Is this legal:
DataStructure -> push_back(std::make_tuple(some_pointer_to_some_int_value, std::ignore, std::ignore));
In next round of data set scanning, I compare the value of some_int_value and upon matching I set following two elements of DataStructure:
DataStructure -> push_back(std::make_tuple(std::ignore, some_bool_value, some_pointer_to_some_int_value2);
I am not sure what exactly std::ignore is for. I tried checking cpp reference website but I did not get it.

I was reading http://en.cppreference.com/w/cpp/utility/tuple/ignore.
And I think you cannot do that because std::ignore is only used as lvalue placeholders.
For example, if you have a return value that you don't want to use, you can do the following.
std::ignore = AFunctionWithAReturnValue();
It cannot be used as a part of rvalue. For your purpose, I'd just fill in placeholder values during the first scanning like this:
std::make_tuple(some_pointer_to_some_int_value, false, nullptr);

Just to elaborate on my previous comment, you cannot use std::ignore here, because it can be used only as lvalue, but really you don't need to either. Just use nullptr or any "default" value instead:
DataStructure->push_back(std::make_tuple(some_pointer_to_some_int_value, false, nullptr));
std::ignore should be used if you want to unpack your tuple into different values like this:
int* p;
bool b;
for (auto& tuple : *DataStructure) {
std::tie(p,b,std::ignore) = tuple;
// p now have value of first element of tuple
// b now have value of second element of tuple
}
On an unrelated note, your second operation does not set values of existing tuple, it adds new one. Also, why use pointer to a vector instead of vector itself or at least std::unique_ptr? It is generaly considered better to omit unnecessary "naked" pointers.

Related

Changing the Value of a paired item in a Map Data structure having a list of items as a value

I could you some help. I have a unordered map data structure, where each map item (key) is a list of (node,value) pairs. see data structure below.
I am changing the value of a paired item in a list using an iterator, but it's not working.
I am wondering how I can get the value changed.
typedef std::unordered_map< std::string, std::list< std::pair<std::string, int> > > di_Acyclic_Graph_Structure;
di_Acyclic_Graph_Structure global_RT;
global_RT["ialu"].push_back(std::make_pair("ialu1",1));
global_RT["ialu"].push_back(std::make_pair("ialu2",1));
adjNodesStructure adjNodes = global_RT["ialu"];
for (auto iterator=adjNodes.begin(); iterator!=adjNodes.end(); iterator++)
{
if (whatever reason)
{
// changing the value of the second item of the
(*iterator).second = 2;
// I expect the value of global["ialu"] -> which gives me a list ialu1, ialu2
// I expect the value of ialu1 to become 2.
// This is not working
}
}
When you use =, and the left-hand-side is not a reference, you are creating a copy of what's on the right side of the =. Thus what is occurring is that you're working on a copy, and not the original item.
Unlike other popular computer languages such as Java, in C++, the = does not automatically use references. If you are used to such languages like Java, C#, etc. this is where C++ becomes a totally different animal.
C++ is a value-based language, where usage of = will make a copy unless you specifically want a reference.
Thus, what you should be doing is to get a reference to the item you want to change.
To get a reference:
adjNodesStructure& adjNodes = global_RT["ialu"];
Note the usage of the declaration of the reference variable using &. Just that one character change in the line makes all the difference.

Why can't I insert objects into a map in c++

So i have a function that is supposed to return a following map:
map<MyObj*, Datastruct>
While trying to insert object from a list which contains said objects:
for(auto element: myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.insert(element.PointerToMyObj, str);
}
Objects in myList contain a pointer to myObj and some properties i need to move from list to a map. Having executed this code in a function below:
map<MyObj*, Datastruct> listToMap = convertList(myList);
I get yelled at by the compiler that:
"no matching function to call to 'std::map::insert(MyObj*&, Datastruct&)"
Here i am helpless. I don't know why compiler would show that i am trying to pass a reference to the function if element in myList(see above) contains
MyObj *PointerToMyObj;
which, the way i see it, is a correct type to pass to the insert function right?
I also tried with
std::make_pair
whereupon compiler yells at me for trying to insert a pair into a
map<MyObj*, Datastruct>.
I am utterly lost. Could someone explain to me what i am doing wrong?
The map's value type is not
std::pair<MyObj*, Datastruct>
but
std::pair<MyObj* const, Datastruct>
Presumably you hardcoded the pair type somewhere, but missed out the const.
Or, if you wrote saidMap.insert(std::make_pair(element.PointerToMyObj, str)) then that should have worked and something else is wrong in your code.
But it's much easier to use emplace:
saidMap.emplace(element.PointerToMyObj, str);
This C++11 version of insert has all the magic machinery needed to make that work "transparently".
Your code is almost alright. You're getting this compiler error because map::insert really doesn't have such overload. It's a tiny detail you've missed on reading up when looking at the std::map documentation. It is so that map::insert doesn't work as implicit constructor, which is how you are trying to use it in the pasted code.
This is something you can achieve by emplacing - map::emplace:
for(auto element : myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.emplace(element.PointerToMyObj, str);
}
Using map::insert(): The insert function is used to insert the key-value pair in the map and has 3 general overloads, in fact, they are more, but these are the main ideas behind how to insert in a map.
insert(pair): simply inserts a new pair in the map, where pair.first is the key and pair.second is the value. Only happens when the key is not already in the map.
insert(it, pair): insert using an iterator and a pair, where it is a pointer to the location where you want to insert your pair at.
insert(begin, end): used for copying the elements from another map by accepting iterators to begin and end of the map.
In your case, you've missed the to actually pass a pair. You can construct it inside of the insert argument list as follows:
for(auto element : myList){
Datastruct str;
str.property1 = element.property1;
str.property2 = element.property2;
saidMap.insert( /*implicitly derive a pair as:*/ { element.PointerToMyObj, str } );
}
Note: This is a post-C++11 functionality, so make sure you're setting compiler's C++ version to at least that.
I've reproduced your code with the working version of the map::insert in Compiler Explorer (godbolt) for you have a look (in both gcc and clang compilers): https://godbolt.org/z/7Mqut0.
Hope this helps!

Erase an element from a map then put it back

Suppose I have a backtracking algorithm where I need to remove an element from a map, do something, then put it back. I am not sure if there is a good way to do it:
func(std::<K, V> map &dict) {
for (auto i : dict) {
remove i from dict;
func(dict);
put i back to dict;
}
}
I know there are ways to delete an element from map in here but I am not sure if there are ways to achieve what I described above. I am aware that I can create a new dict in for loop and pass it in func but I am wondering if it can be done using the same dict.
What you ask is definitely possible. Here is one way to do it while trying to keep things simple and efficient:
void func(std::map<K, V> &dict) {
for (auto i = dict.cbegin(); i != dict.cend(); ) {
auto old = *i;
i = dict.erase(i); // i now points to the next element (or dict.end())
some_other_func(dict);
dict.insert(i, old); // i is used a hint where to re-insert the old value
}
}
By calling std::map::erase with an iterator argument and std::map::insert with a hint, the complexity of each iteration through this loop is amortized constant. Note that I assumed your calling of func in line 5 was actually supposed to be some_other_func, because calling func recursively would invalidate the iterator you carefully set in line 4.
However, this is not the most efficient way to do this sort of processing (#rakurai has a suggestion that should be considered).
This question has an answer here.
However, your problem may be that you would like the function to ignore the key K while processing dict. How about a second parameter "K ignore" and make the function skip that pair? You could give it a default value in the declaration if that breaks other code, or overload the function.

Alternative to nested maps in standard namespace

I have nested map of type:
std::map<int,std::map<pointer,pointer>>
I am iterating over the map each time/per frame and doing updates on it.So basically I have 2 nested if loops.
i have an array and i need to sort the data with 2 attributes. First attribute is integer which is the first key, then second attribute is a pointer which is a key of nested map inside the main map. so my code is something like:
iterator = outermap.find();
if(iterator!=outermap.end()){
value = iterator->second;
it1 = value.find();
if(it1!=value.end(){
value1 = it1->second;
// do something
}
else{
// do something and add new value
}
}
else {
// do something and add the values
}
This is really slow and causing my application to drop frame rate. Is there any alternative to this? Can we use hash codes and linked list to achieve the same?
You can use std::unordered_map, it will hash the keys so finds complete faster. Using value = iterator->second is copying your entire map to the 'value' variable. Using a reference avoids unnecessary copying and is better for performance, eg: auto & value = iterator->second.
Also std::map is guaranteed to be ordered. This can be used to your advantage since your keys are integers for the outermost map.
Firstly, your question is a bit vague, so this may or may not fit your problem.
Now, you have a map<int, map<pointer, pointer>>, but you never operate on the inner map itself. All you do is look up a value by an int and a pointer. This is also exactly what you should do instead, use an aggregate of those two as key in a map. The type for that is pair<int, pointer>, the map then becomes a map<pair<int, pointer>, pointer>.
One more note: You seem to know the keys to search in the map in advance. If the check whether the element exists is not just for safety, you could also use the overloaded operator[] of the map. The lookup then becomes outermap[ikey][pkey] and returns a default-initialized pointer (so probably a null pointer, it pointer really is a pointer). For the suggested combined map, the lookup would be outermap[make_pair(ikey, pkey)].

Is it at all possible to erase from a vector with C++11's for loops?

Alright. For the sake of other (more simple but not explanatory enough) questions that this might look like, I am not asking if this is possible or impossible (because I found that out already), I am asking if there is a lighter alternative to my question.
What I have is what would be considered a main class, and in that main class, there is a variable that references to a 'World Map' class. In essence, this 'WorldMap' class is a container of other class variables. The main class does all of the looping and updates all of the respective objects that are active. There are times in this loop that I need to delete an object of a vector that is deep inside a recursive set of containers (As shown in the code provided). It would be extremely tedious to repeatedly have to reference the necessary variable as a pointer to another pointer (and so on) to point to the specific object I need, and later erase it (this was the concept I used before switching to C++11) so instead I have a range for loop (also shown in the code). My example code shows the idea that I have in place, where I want to cut down on the tedium as well as make the code a lot more readable.
This is the example code:
struct item{
int stat;
};
struct character{
int otherStat;
std::vector<item> myItems;
};
struct charContainer{
std::map<int, character> myChars;
};
int main(){
//...
charContainer box;
//I want to do something closer to this
for(item targItem: box.myChars[iter].myItems){
//Then I only have to use targItem as the reference
if(targItem.isFinished)
box.myChars[iter].myItems.erase(targItem);
}
//Instead of doing this
for(int a=0;a<box.myChars[iter].myItems.size();a++){
//Then I have to repeatedly use box.myChars[iter].myItems[a]
if(box.myChars[iter].myItems[a].isFinished)
box.myChars[iter].myItems.erase(box.myChars[iter].myItems[a]);
}
}
TLDR: I want to remove the tedium of repeatedly calling the full reference by using the new range for loops shown in C++11.
EDIT: I am not trying to delete the elements all at once. I am asking how I would delete them in the matter of the first loop. I am deleting them when I am done with them externally (via an if statement). How would I delete specific elements, NOT all of them?
If you simply want to clear an std::vector, there is a very simple method you can use:
std::vector<item> v;
// Fill v with elements...
v.clear(); // Removes all elements from v.
In addition to this, I'd like to point out that [1] to erase an element in a vector requires the usage of iterators, and [2] even if your approach was allowed, erasing elements from a vector inside a for loop is a bad idea if you are not careful. Suppose your vector has 5 elements:
std::vector<int> v = { 1, 2, 3, 4, 5 };
Then your loop would have the following effect:
First iteration: a == 0, size() == 5. We remove the first element, then the vector will contain {2, 3, 4, 5}
Second iteration: a == 1, size() == 4. We then remove the second element, then the vector will contain {2,4,5}
Third iteration: a == 2, size() == 3. We remove the third element, and we are left with the final result {2,4}.
Since this does not actually empty the vector, I suppose it is not what you were looking for.
If instead you have some particular condition that you want to apply to remove the elements, it is very easily applied in C++11 in the following way:
std::vector<MyType> v = { /* initialize vector */ };
// The following is a lambda, which is a function you can store in a variable.
// Here we use it to represent the condition that should be used to remove
// elements from the vector v.
auto isToRemove = [](const MyType & value){
return /* true if to remove, false if not */
};
// A vector can remove multiple elements at the same time using its method erase().
// Erase will remove all elements within a specified range. We use this method
// together with another method provided by the standard library: remove_if.
// What it does is it deletes all elements for which a particular predicate
// returns true within a range, and leaves the empty spaces at the end.
v.erase( std::remove_if( std::begin(v), std::end(v), isToRemove ), std::end(v) );
// Done!
I am deleting them when I am done with them externally (via an if statement). How would I delete specific elements, NOT all of them?
In my opinion, you're looking at this the wrong way. Writing loops to delete items from a sequence container is always problematic and not recommended. Strive to stay away from removing items in this fashion.
When you work with containers, you should strategically set up your code so that you place the deleted or "about to be deleted" items in a part of the container that is easily accessed, away from the items in the container that you do not want to delete. At the time you actually do want to remove them, you know where they are and thus can call some function to expel them from the container.
One answer was already given, and that is to use the erase-remove(if) idiom. When you call remove or remove_if, the items that are "bad" are moved to the end of the container. The return value for remove(_if) is the iterator to the start of the items that will be removed. Then you feed this iterator to the vector::erase method to delete these items permanently from the container.
The other solution (but probably less used) is the std::partition algorithm. The std::partition also can move the "bad" items to the end of the container, but unlike remove(_if), the items are still valid (i.e. you can leave them at the end of the container and still use them safely). Then later on, you can remove them as you wish in a separate step since std::partition also returns an iterator.
Why not have a standard iterator iterating over a vector. That way you can delete the element by passing an iterator. Then .erase() will return the next available iterator. And if your next iterator is iterator::end() then your loop will exit.