Programming: several C++ container classes

In our live Arkanoid coding sessions, we used several standard C++ container classes. I am going to describe them in this post.

std::pair

An array contains multiple elements of the same type. Sometimes, however, it is useful to hold two objects (possibly of different types) as a single entity. For this purpose, we use the std::pair container.

Below is a table with basic personal data:

Id Name
100 John

It is natural to group Id and Name and refer to them as a single object within the body of a program. The following declaration establishes this grouping:

int id = 100;
std::string name = “John”;
std::pair entry (id, name);

You can now refer to the object entry which contains both the id = 100 and the name = John.

std::pair has two important member variables, first and second to obtain the elements grouped within. So if we were to access the values in entry, we would use

std::cout << entry.first << std::endl;
std::cout << entry.second;

The above code would produce

100
John

std::map

Suppose you want to contain a number of such std::pair‘s. E.g., you have the following table:

Id Name
100 John
101 Mary
102 Peter

Here you would use the std::map container which behaves like an “array” (or, rather, a vector) of std::pair‘s.

int john = 100;
std::string John = “John”;
std::pair entry1 (john, John);
int mary = 101;
std::string Mary = “Mary”;
std::pair entry2 (mary, Mary);
int peter = 102;
std::string Peter = “Peter”;
std::pair entry3 (peter, Peter);
std::map people;
people.insert(entry1);
people.insert(entry2);
people.insert(entry3);

The code above declares the map people and adds the three std::pair‘s to it by using the class’s .insert() method.

Accessing the pairs and their elements is a little bit more involved. Let’s say I want to refer to the second entry (Mary). Then I have to define something called an iterator. An iterator is a special pointer that points to a particular element in a container class like std::map. So if you include the following line:

auto it = people.find(101);

you will create an iterator, it, which will find the entry whose first value (called the key) is 101 and refer to that whole std::pair within the map.

Once the iterator is set up, you can use it to obtain the actual elements of that std::pair. Since the iterator is a pointer, first you have to dereference it to access the actual std::pair and not its memory address; then you use the first and second member variables to obtain the very elements held within the std::pair:

std::cout << (*it).second << std::endl;

The above line is equivalent to

std::cout <second << std::endl;

where the -> operator is used to access the value via the pointer (iterator) without explicitly dereferencing it. Both lines result in Mary being printed out.

NB: auto refers to the type of the iterator we’re defining. Since I’m creating an iterator for an std::map container, we need to write

std::map::iterator it = people.find(101);

which explicitly defines the type of the iterator – it belongs to an std::map that contains std::pair‘s of int‘s and std::string‘s. But the particular map for which the iterator is being created is written out explicitly on the right – it’s people, so the type of the iterator is known at the time it is being defined. Therefore, you can use replace the lengthy left-hand side of the assignment statement with the auto keyword which tells the compiler to derive the type of the iterator automatically from the right-hand side.

About Rokas Paulauskas

2014  Programming