C++ Pointers
Objects, structs and STL Containers

Introduction

All the literature (both on-line and textbooks) I referenced to learn how to use STL containers only showed how to use them to hold primitives, (e.g. integers, strings, etc.), and made no mention of how to handle objects or structs.

This C++ Pointer shows you how to manipulate objects and structs stored in an STL Vector and an STL Map. There are other STL containers, but once the use of these two containers is known the same techniques can be used for the others.

The first version of this code was written around 2005, in 2023 I updated the code to use C++11, C++14 and C++17 updates. The following updates have been made;

Overview of the Example Programs

To make the example relatable and easily understandable and focus on the code required for using the STL container, rather than the application, the example code uses a simple Class (ColourCode.cpp) and struct (ColourCodeStruct) that contain the name of a colour and its Red, Green and Blue colour values. Consequently, the use cases are very simple, but make it easier to focus on how to use an object or struct stored in an STL container.

How to use this object and struct in an STL Vector is shown in VectorExample.cpp and in MapExample.cpp for an STL Map.

The example programs have identical functionality. A container to hold the ColourCode objects and another to hold the structs are created and then passed by reference to an object of Loader. This loads the containers with ColourCode objects and structs that contain the colour information for the basic web browser colours.

Iterators for the containers are created and are used to step through the contents of the container. For each object and struct in the container details of the object and struct are extracted and written to a file, (VectorExample_res.txt or MapExample_res.txt). Then the colour named custom1 is located in the container and its properties modified to khaki. The contents of the container are then written to the file.

This C++ Pointer assumes you know how to use a Vector or Map to hold primitives, as this is widely described in literature. If you want to know how to use the STL Vector or Map check out www.cppreference.com/cppstl.html or Google etc., for information on the Standard Template Library.

Please note that this C++ Pointer is distributed with
NO WARRANTY

Section 5 Disclaimer of Warranties and Limitation of Liability.

  1. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
  2. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
  3. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
.

How to Create a Map and Vector of objects or structs

A Vector or Map of objects is created in the same way that a Vector or Map of primitives is created. An example of the simplest manner in which they are created is as follows;

std::vector<std::unique_ptr<ColourCode>> colourCodeObjects; std::map<string, std::unique_ptr<ColourCode>> colourCodeObjects;

The creation of a Vector or Map of structs follows the same format,

std::vector<std::unique_ptr<ColourCodeStruct>>: colourCodeStructs; std::map<string, std::unique_ptr<ColourCodeStruct>> colourCodeStructs;

How to Add an Object or a struct to an STL Vector

The emplace_back function enables the creation of a object or struct in place, rather than using a create and copy. Because I often work with loading variable length data I like to add an empty object and then load data into it, rather than loading all the data and creating the object, which results in the last object having to be added outside the data import loop. Having to add the last object outside the data import loop means extending the object's lifespan and makes code maintainence harder if there is additional work in the application when an object is created.

In the following example on how to add an object or struct I create add an empty object and then get an iterator to it, and update the newly added object. Of course, if you want to add a "full" object, then there is no need to create the iterator.

colourCodes.emplace_back(std::make_unique<ColourCode>(args)); std::vector<std::unique_ptr<ColourCode>>::iterator itr = std::prev(colourCodes.end(), 1); itr->get()->member_funtion(); colourCodesStructs.emplace_back(std::make_unique<ColourCodeStruct>()); std::vector<std::unique_ptr<ColourCodeStruct>>::iterator itr = std::prev(colourCodeStructs.end(), 1); itr->get()->name = name;

In the example above args are any arguments you want to forward for the construction of the object.
As the iterator returned is to a std::unique_ptr<object> or std::unique_ptr<struct> we have to get() the contained pointer to the actual object or struct.

How to Add an Object or a struct to an STL Map

For Map I use the emplace function to create the object or struct in place, for the same reasons described above for the Vector. In the following example on how to add an object or struct I create add an empty object and then get an iterator to it, and update the newly added object. Of course, if you want to add a fully constructed object, then there is no need to create the iterator. Even if you create the object in place you may still want to "get" the return value to test if the object or struct was added, or if it was not.

In the example below, insertedElement is a std::pair<std::pair< key, iterator>, bool>, where key is the key referencing the inserted element, iterator is an iterator referencing the inserted element, and bool is true if the insertion happened, and false if it did not.

auto insertedElement = colourCodes.emplace(std::pair<std::string, std::unique_ptr<ColourCode>>(key, std::make_unique<ColourCode>(args))); if (insertedElement.second) { /* Entry was added / inserted. Perform application specific actions. In this example, update the inserted element with data */ while (getdata) { insertedElement.first->second->member_funtion(data); } } else { /* Entry was not added / inserted. Perform application specific actions. In this example, write an warning message */ stream << "Key " << insertedElement.first->first << " not inserted. Existing values are " << insertedElement.first->second->toString(); /* Update the existing element with data? */ while (getdata) { insertedElement.first->second->member_funtion(data); } } auto insertedElement = colourCodes.emplace(std::pair<std::string, std::unique_ptr<ColourCodeStruct>>(key, std::make_unique<ColourCodeStruct>())); if (insertedElement.second) { …

You can also use std::make_pair to create the key and object or struct pair to be added to the Map, see the file Loader.cpp.

How to Create an Iterator for STL Maps and Vectors of objects or structs

An Iterator for a Vector or Map of objects or structs is created the same way as if it was being created for a Vector or Map of primitives, for example,

vector<ColourCode>::iterator cCOItr; vector<ColourCodeStruct>::iterator cCSItr; map<string,ColourCode>::iterator cCOItr; map<string,ColourCodeStruct>::iterator cCSItr;

However the addition of type deduction, (auto) to the language simplifies iterator creation.

How to Find an Object or structStored in an STL Vector

An object or struct can be found in an STL Vector using the STL algorithm find_if, the same way that it would be used for a Vector of primatives.

Note, in my code I'm using std::unique_ptr<…>s, so need to use std::unique_ptr.get() to access the managed object or struct, for example,
returned_iterator->get()->member_function.

How to Access the Member Function of an Object Stored in an STL Vector

To access the member functions of an object in a Vector you create an Iterator to the Vector, (cCOItr in this example) and then treat the iterator as a pointer to the object and use the -> (structure pointer dereference) operator in place of the dot operator to access the object's member function. For example;

std::string name = cCOItr->getName(); cCOItr->changeName("khaki");

How to Access the elements of a struct stored in an STL Vector

To access the elements of a struct in a Vector you create an Iterator to the Vector, (cCSItr in this example) and then treat the iterator as a pointer to the struct and use the -> (structure pointer dereference) operator as normal. For example;

std::cout << cCSItr->name; cCSItr->red = 0xF0;

How to pass an Object Stored in an STL Vector into a Function

An object in a Vector can be passed into a function that takes a reference to the object, by dereferencing the iterator (cCOItr in this example). For example;

output(fout, *cCOItr); … void output(std::ofstream &fout, ColourCode &colourCode) { if (colourCode.isDefined()) { …

Note, in the function the object referenced by the iterator is now treated as if it is an object so the member functions are referenced using the . (dot) operator.

How to Access the Member Function of an Object Stored in an STL Map

To access the member function of an object in a Map you create an Iterator to the Map, (cCOItr in this example) and use it to select the object you are interested in as applicable. Use the -> (arrow) (structure pointer dereference) operator to access the object which is the second parameter of the iterator and then use dot notation to access the object's member function as follows;

std::string name = cCOItr->second.get()->getName(); cCOItr->second.get()->changeName("khaki");

Note, in my code I'm using std::unique_ptr<…>s, so need to use std::unique_ptr.get() to access the managed object.

From C++ 17 auto can be used to create a std::pair<Key, Element> iterator and we can use Key and Element rather than ->first and ->second, for example

for (auto& [key, cCO] : colourCodeObjects) { fout << key; fout << cCO->name(); }

How to Access the elements of a struct Stored in an STL Map

To access the elements of a struct in a Map you create an Iterator to the Map, (cCSItr in this example) and use it to select the struct you are interested in as applicable. Use the -> (structure pointer dereference) operator to access the struct which is the second parameter of the iterator and then use dot notation to access the element of the struct. For example;

std::cout << cCSItr->second.get()->name; cCSItr->second.get()->red = 0xF0;

Note, in my code I'm using std::unique_ptr<…>s, so need to use std::unique_ptr.get() to access the managed struct.

From C++ 17 auto can be used to create a std::pair<Key, Element> iterator and we can use Key and Element rather than ->first and ->second, for example

for (auto& [key, cCS] : colourCodeStructs) { fout << key; fout << cCS->name; }

How to pass an Object Stored in an STL Map into a Function

An object in a Map can be passed into a function that either;
takes the reference of a Map Iterator, which you can do if you also want the value of the Map Key, for example;

output(fout, cCOItr); … void output(std::ofstream &fout, std::map<std::string, std::unique_ptr<ColourCode>>::iterator &cCOItr) { if (cCOItr->second.get()->isDefined()) { … cCOItr->second.get()->getRGB(red,green,blue); … << cCOItr->first << …

Note, in my code I'm using std::unique_ptr<…>s, so need to use std::unique_ptr.get() to access the managed object.

Note, because we are passing an iterator into the iterator reference parameter of the function, the iterator is not dereferenced in the function call, and within the function the variable is an iterator and the first and second parameters of the iterator are referenced with the -> (arrow) (pointer dereference) operator.

Or, if you only want the object, the second parameter of the Map iterator can be passed into a function that takes a reference to the object, for example;

output(fout, *cCOItr->second); … void output(std::ofstream &fout, ColourCode &colourCode) { if (colourCode.isDefined()) { …

Note, in the function the object referenced by the iterator is now treated as if it is an object so the member functions are referenced using the . (dot) operator.

Software for Download and Installation

This C++ Pointer was compiled and tested using Apple clang version 14.0.0 on x86_64-apple-darwin22.3.0 and with Windows 10 using cygwin-3.2.0, gcc version 10.2.0

To obtain the source code, install and execute this C++ Pointer use the following procedure.

Description
Shell Commands
Download CppPtr1.tar.gz and save to a folder
 
Extract CppPtr1.tar.gz
Open a terminal window, navigate to the folder and expand the file using the command
$ tar -xvzf CppPtr1.tar.gz
This will create the folder CppPtr1 and place the source files in it
 
Go to the CppPtr1 folder
$ cd CppPtr1
Use your favourite text editor to view the files VectorExample.cpp and MapExample.cpp which contain the code to demonstrate using objects and structs in a Vector and a Map respectively
 
Optionally
Build the executables
$ make
Run the examples
$ ./VectorExample
$ ./MapExample
Use your favourite text editor to view the results files
 

Revision History

Rev
Date
Details
0.0
27-Oct-2021
Initial version
1.0
11-Apr-2023
Updated to use C++11, C++14 and C++17 features

Technical Support

Bug-Reports

If you suspect a bug please e-mail a description being sure to identify that the bug report is about C++ Pointer #1 and include as much detail as possible.