Pointer to a map - c++

If I define a pointer-to-map like this:
map<int, string>* mappings;
mappings is a pointer. How should I use this pointer to operate the map?

Use the pointer just like you use any other pointer: dereference it to get to the object to which it points.
typedef std::map<int, string>::iterator it_t;
it_t it1 = mappings->begin(); // (1)
it_t it2 = (*mappings).begin(); // (2)
string str = (*mappings)[0]; // (3)
Remember that a->b is — mostly — equivalent to (*a).b, then have fun!
(Though this equivalence doesn't hold for access-by-index like (*a)[b], for which you may not use the -> syntax.)

Not much difference except that you have to use -> for accessing the map members. i.e.
mapping->begin() or mapping->end()
If you don't feel comfortable with that then you can assign a reference to that and use it as in the natural way:
map<int, string> &myMap = *mappings; // 'myMap' works as an alias
^^^^^^^^
Use myMap as you generally use it. i.e.
myMap[2] = "2";
myMap.begin() or myMap.end();

For instance:
#include <map>
#include <string>
#include <iostream>
int main() {
std::map<int, std::string> * mapping = new std::map<int, std::string>();
(*mapping)[1] = "test";
std::cout << (*mapping)[1] <<std::endl;
}

With the introduction of "at" function in c++ 11, you can use mappings->at(key) instead of (*mapping)[key].
Keep in mind that this api will throw out_of_range exception if the key is not already available in the map.

another nice way of using pointers, which I like is calling mappings->(and the function you want to call)

Well, STL is designed to reduce the complexity of pointer handling..so better approach is to use stl::iterator.. try to avoid pointers :-/

Related

C++: is it possible to use "universal" pointer to vector?

Good day, SO community!
I am new to C++ and I've ran into a situation in my project, where I have 2 vectors of similar paired data types:
std::vector<std::pair<int, std::string> firstDataVector
std::vector<std::pair<int, std::string> secondDataVector
and in one part of the code I need to select and process the vector depending on the external string value. So my question is - is it possible to create a pointer to vector outside of the conditions
if (stringValue.find("firstStringCondition"))
{
//use firstDataVector
}
if (stringValue.find("secondStringCondition"))
{
//use secondDataVector
}
some kind of pDataVector pointer, to which could be assigned the existing vectors (because now project has only two of them, but the vectors count might be increased)
I've tried to createstd::vector<std::string> &pDataVector pointer, but it will not work because reference variable must be initialized. So summarizing the question - is it possible to have universal pointer to vector?
You are trying to create a reference to one of the vectors - and that's certainly possible, but it must be initialized to reference it. You can't defer it.
It's unclear what you want to happen if no match is found in stringValue so I've chosen to throw an exception.
now project has only two of them, but the vectors count might be increased
Create a vector with a mapping between strings that you would like to try to find in stringValue and then the vector you'd like to create a reference to.
When initializing pDataVector, you can call a functor, like a lambda, that returns the reference.
In the functor, loop over the vector holding the strings you'd like to try to find, and return the referenced vector on the first match you get.
It could look like this:
#include <functional>
#include <iostream>
#include <string>
#include <vector>
int main() {
using vpstype = std::vector<std::pair<int, std::string>>;
vpstype firstDataVector{{1, "Hello"}};
vpstype secondDataVector{{2, "World"}};
// A vector of the condition strings you want to check keeping the order
// in which you want to check them.
std::vector<std::pair<std::string, std::reference_wrapper<vpstype>>>
conditions{
{"firstStringCondition", firstDataVector},
{"secondStringCondition", secondDataVector},
// add more mappings here
};
// an example stringValue
std::string stringValue = "ssdfdfsdfsecondStringConditionsdfsfsdf";
// initialize the vpstype reference:
auto& pDataVector = [&]() -> vpstype& {
// loop over all the strings and referenced vpstypes:
for (auto& [cond, vps] : conditions) {
if (stringValue.find(cond) != std::string::npos) return vps;
}
throw std::runtime_error("stringValue doesn't match any condition string");
}();
// and use the result:
for (auto [i, s] : pDataVector) {
std::cout << i << ' ' << s << '\n'; // prints "2 world"
}
}
You can indeed inintialize references conditionally. Either use a function or lambda that returns the vector you want to reference, or hard code it like below.
std::vector<std::string> &pDataVector =
(stringValue.find("firstStringCondition") != std::string::npos) ?
firstDataVector : ((stringValue.find("secondStringCondition") != std::string::npos) ?
secondDataVector : thirdDataVector);

map.find(var) isn't returning correct value

Sample code is :
map<char* , int> map;
map["Privilege"] = 1;
char* code[]="Privilege";
val = map.find(code); // returns map.end()
val = map.find("Privilege"); // returns correct value
I need to find the value in the map on the basis of variable key :
val = map.find(code);
It is returning map.end()
Please suggest something
Use std::string instead of char *
Since you want to save the string value, not its location.
Also, I wouldn't use the name "map" for a variable (since its already used)
#include <map>
#include <string>
std::map<std::string, int> mymap;
mymap["Privilege"] = 1;
std::string code = "Privilege";
val = mymap.find(code);
val = mymap.find("Privilege");
You're storing character pointers in your map, not strings. map.find compared the two pointers and finds them not equal.
Just use a map<string, int> .
In C++ application do not use char*, use string instead. I mean, define map as map<string , int> MyMap;
By the way, map is not good name for variable :-)

Is it possible to iterate over an iterator?

I have a working program that capitalizes strings in a vector, using iterators:
vector<string> v7{ 10, "apples" };
for (auto vIterator= v7.begin(); vIterator!= v7.end(); ++vIterator){
auto word = *vIterator; //here
auto charIterator = word.begin();
*charIterator = toupper(*charIterator);
*vIterator = word; //also here, i guess i could just print `word` instead?
cout << *vIterator << endl;
}
My question is;
2nd line inside the loop # the comment, i had to save the pointer to the iterator to another string variable before i was able to iterate over it.
Iterating over the pointer like so
*vIterator.begin();
didn't seem to work.
Is this the correct practice, or am i missing something?
I'm new to the C languages, the concept behind pointer-like tools is quite hard to understand even if i can use them, and in this case it just feels like I'm doing it wrong.
Edit: It was a syntax error (*vIterator).begin();
It just didn't make sense why i'd have to save it to another variable before iterating over it, cheers.
Since you are using C++11 look how simpler your code can become using ranged loops like the example below:
std::vector<std::string> v(10, "apples");
for(auto &&word : v) {
word[0] = toupper(word[0]);
}
LIVE DEMO
Now as far as it concerns the (*vIterator.begin(); didn't seem to work.):
The dot operator (i.e., .) has a higher precedence than the dereference operator (i.e., *). Thus, *vIterator.begin() is interpreted as *(vIterator.begin()). The compiler rightfully complains because vIterator hasn't got a member begin().
Think of iterators as if they were pointers. The correct way to access the members of an object via a pointer/iterator pointing to it is either using the arrow operator (i.e., vIterator->begin()) or first dereference the pointer/iterator and then use the dot operator (i.e., (*vIterator).begin()).
So your code via the use of iterators would become:
std::vector<std::string> v(10, "apples");
for(auto it(v.begin()), ite(v.end()); it != ite; ++it) {
*(it->begin()) = toupper(*(it->begin()));
}
LIVE DEMO
The correct way to write *vIterator.begin(); is (*vIterator).begin(); or, more often, vIterator->begin();. Also note that you can also access the first character of a string directly (without having to iterate over it) as word[0].
A simple STL-ish way of doing it:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
vector<string> v7{ 10, "apples" };
for_each(v7.begin(), v7.end(), [](string& word){word[0] = toupper(word[0]);});
}

Shorter way to get an iterator for a std::vector

Lets say that I have got a vector like this.
std::vector<a_complicated_whatever_identifier *> *something
= new std::vector<a_complicated_whatever_identifier *>;
// by the way, is this the right way to do this?
Now I want to get an iterator for this... so I would do this like this.
std::vector<a_complicated_whatever_identifier *>::iterator iter;
But I find it a little too much for my code. I wonder, is there any more, brief way to ask for an iterator regardless of the type?
I was thinking in something like.
something::iterator iter;
// OK, don’t laugh at me, I am still beginning with C++
Well, it obviously fail, but I guess you get the idea. How to accomplish this or something similar?
You would typically give your containers sensible typedefs, and then it's a breeze:
typedef std::pair<int, Employee> EmployeeTag;
typedef std::map<Foo, EmployeeTag> SignInRecords;
for (SignInRecords::const_iterator it = clock_ins.begin(); ... )
^^^^^^^^^^^^^^^^^
Usually, having a handy typedef for the container is more practical and self-documenting that an explicit typedef for the iterator (imagine if you're changing the container).
With the new C++ (11), you can say auto it = clock_ins.cbegin() to get a const-iterator.
Use a typedef.
typedef std::vector<complicated *>::iterator complicated_iter
Then set them like this:
complicated_iter begin, end;
In C++11 you'll be able to use auto.
auto iter = my_container.begin();
In the meantime just use a typedef for the vector:
typedef std::vector<a_complicated_whatever_identifier *> my_vector;
my_vector::iterator iter = my_container.begin();
You should rarely have much need/use for defining an iterator directly. In particular, iterating through a collection should normally be done by a generic algorithm. If there's one already defined that can do the job, it's best to use it. If there's not, it's best to write your own algorithm as an algorithm. In this case, the iterator type becomes a template parameter with whatever name you prefer (usually something referring at least loosely to the iterator category):
template <class InputIterator>
void my_algorithm(InputIterator start, InputIterator stop) {
for (InputIterator p = start; p != stop; ++p)
do_something_with(*p);
}
Since they've been mentioned, I'll point out that IMO, typedef and C++11's new auto are (at least IMO) rarely a good answer to this situation. Yes, they can eliminate (or at least reduce) the verbosity in defining an object of the iterator type -- but in this case, it's basically just treating the symptom, not the disease.
As an aside, I'd also note that:
A vector of pointers is usually a mistake.
Dynamically allocating a vector is even more likely a mistake.
At least right off, it looks rather as if you're probably accustomed to something like Java, where you always have to use new to create an object. In C++, this is relatively unusual -- most of the time, you want to just define a local object so creation and destruction will be handled automatically.
// by the way, is this the right way to do this?
What you are doing is correct. The best approach depends on how you want to use that vector.
But I find it a little too much for my code. I wonder, is there any
more, brief way to ask for an iterator regardless of the type?
Yes, you can define the vector as a type:
typedef std::vector<a_complicated_whatever_identifier *> MyVector;
MyVector * vectPtr = new MyVector;
MyVector::iterator iter;
If you have a recent compiler, I suggest giving c++11 a spin. Most compilers support it in the form of the --std=c++0x flag. You can do all kinds of nifty things related to type inference:
std::list<std::map<std::string, some_complex_type> > tables;
for (auto& table: tables)
{
std::cout << table.size() << std::endl;
}
for (auto it = tables.begin(); it!= tables.end(); ++it)
{
std::cout << it->size() << std::endl;
}
Also look at decltype and many other handyness:
// full copy is easy
auto clone = tables;
// but you wanted same type, no data?
decltype(tables) empty;
Contrived example of combining typedefs with the above:
typedef decltype(tables) stables_t;
typedef stables_t::value_type::const_iterator ci_t;

getting object in each element in vector

Is there a way for an iterator to return an object in each element of a C++ Standard Library vector?
I have this code:
struct mystruct {
int field1;
}
int DoSomethingWithMyStruct(mystruct& a);
std::vector<mystruct> myVector;
std::vector<mystruct>::iterator it;
mystruct s1,s2, temp;
s1.field1=1;
s2.field1=2;
for (it=myVector.begin();it!=myVector.end();it++)
{
//I want to call DoSomethingWithMyStruct, so I have to pass in mystruct object.
//can I use iterator to get the object of each element in myVector without having to create a temporary mystruct object and pass it in?
//I'm looking for an easier way than having to do this:
temp.field1 = it->field1;
DoSomethingWithMyStruct(temp);
}
As well as what the others said, you can do this instead:
#include <algorithm>
std::for_each(myVector.begin(), myVector.end(), DoSomethingWithMyStruct);
It's short and succinct. No need of manual loop.
Yes:
DoSomethingWithMyStruct(*it);
Just dereference the iterator, surely:
std::vector<mystruct>::iterator it, end;
for (it = myVector.begin(), end = myVector.end(); it != end; ++it) {
DoSomethingWithMyStruct(*it);
}
Or am I missing something here...?
Going further, there are other ways to iterate. You could use BOOST_FOREACH or C++0x ranged-for to simplify the loop. You could also use an algorithm like std::for_each to remove it entirely!
(Remember that it->field1 is like (*it).field1, so you're already doing this... even though you're going on to make your code more complicated than is necessary afterwards!)
Just simply dereference your iterator. *it, and you get a mystruct. They behave like pointers in this regard.
But in the case if you wonder how to iterate over all fields of all elements of a vector, where the elements are polymorphic; e.g. std::vector<Base*>, it's a bit more difficult. Since C++ doesn't have reflection that would make this possible (semi)automatically, you need to do it manually. Something similar to the Visitor Pattern comes to mind.
You have not populated myVector
Could make code more efficent like this
std::vector<mystruct>::const_iterator theEnd;
for (it=myVector.begin();it!=theEnd;++it)
Notice the position of the ++
I think that &(*it) should work.