Home C++ Introduction Decisions Loops Input/Output Functions Stack and Heap References Arrays Searching and Sorting Recursion Pointers Character and Strings Structures Classes Inheritance Exceptions Templatess STL Modern C++ Misc Books ----

Contents

Introduction



The STL ( Standard Template Library) is a set of C++ classes and functions that implement common data structures and algorithms. They are usually based on templates to allow generic use.

Containers



Containers contain collection of objects. We have several kinds such as vector, map, queue, list. Advantage of these over arrays is that they can grow and memory is taken care of internally.
File: v1.cpp
#include <iostream>
#include <vector>
using namespace std;

int main()
{

   // create a vector to store int
   vector<int> vec;
   int i1;

   // display the original size of vec
   cout << "vector size = " << vec.size() << endl;

   // push 5 values into the vector
   for(i1 = 0; i1 < 5; i1++)
   {
      vec.push_back(i);
   }

   // display extended size of vec
   cout << "extended vector size = " << vec.size() << endl;

   // access 5 values from the vector
   for(i1 = 0; i1 < 5; i1++)
   {
      cout << "value of vec [" << i1 << "] = " << vec[i1] << endl;
   }

   // use iterator to access the values
   vector<int>::iterator iter = vec.begin();
   while( iter != vec.end())
   {
      cout << "value of v = " << *iter << endl;
      iter++;
   }

   return 0;
}
$ g++ v1.cpp ; ./a.exe
vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4

We use the "push_back" function to push the object to the end of the vector. The STL containers make copy of what we push to place in the container. If we look at the definition of the "push_back" call it looks like:
void push_back (const value_type& val);
Even though it seems to be taking a reference the STL eventually makes a copy somewhere stores the copy somewhere.
File: v2.cpp
#include <iostream>
#include <vector>
using namespace std;

class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};



int main()
{

   // create a vector to store int
   vector<student> vec;
   int i1;
   student studentObj( 1 ) ;


   // display the original size of vec
   cout << "vector size = " << vec.size() << endl;


   vec.push_back( studentObj );


   // display extended size of vec
   cout << "extended vector size = " << vec.size() << endl;


   cout << "value of vec [" << 0 << "] = " << vec[0].id << endl;



   return 0;
}
$ g++ v2.cpp  ; ./a.exe
Constructor called for  ;1
vector size = 0
Copy Constructor called for  ;1
extended vector size = 1
value of vec [0] = 1
Destructor called for  ;1
Destructor called for  ;1
If we do not want a copy then we can use pointers.
File: v3.cpp
#include <iostream>
#include <vector>
using namespace std;
//Use pointers to avoid a copy


class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};



int main()
{

   // create a vector to store int
   vector<student*> vec;
   int i1;
   //student studentObj( 1 ) ;
   student* ptr ;
   ptr = new student( 1 ) ;

   // display the original size of vec
   cout << "vector size = " << vec.size() << endl;

   // push 5 values into the vector
   vec.push_back( ptr );


   // display extended size of vec
   cout << "extended vector size = " << vec.size() << endl;


     cout << "value of vec [" << 0 << "] = " << vec[0]->id << endl;



   delete ptr ;
   return 0;
}
This works but there are a couple of problems with this approach. We must remember to delete the pointer but only once and there is another copy in the vector object. If we delete the pointer first and then somewhere in the code the vector is used to access the object then the program does not work correctly.
File: v4.cpp
#include <iostream>
#include <vector>
using namespace std;
//Use pointers to avoid a copy


class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};



int main()
{

   // create a vector to store int
   vector<student*> vec;
   int i1;
   //student studentObj( 1 ) ;
   student* ptr ;
   ptr = new student( 1 ) ;

   // display the original size of vec
   cout << "vector size = " << vec.size() << endl;

   // push 5 values into the vector
   vec.push_back( ptr );


   // display extended size of vec
   cout << "extended vector size = " << vec.size() << endl;

   // access 5 values from the vector
      cout << "value of vec [" << 0 << "] = " << vec[0]->id << endl;


   // use iterator to access the values
   delete ptr ;

   //Using the vector after the object has been deleted.
   cout << "value of vec [" << 0 << "] = " << vec[0]->id << endl;

   return 0;
}
$ g++ v4.cpp  ; ./a.exe
Constructor called for  ;1
vector size = 0
extended vector size = 1
value of vec [0] = 1
Destructor called for  ;1
value of vec [0] = -631185240
How do we take care of this problem. It's smart pointers to the rescue. A smart pointer is a wrapper around the raw pointer and takes care of certain details for us.

Smart Pointer

We have 2 different kinds of smart pointers with C++: unique pointer and shared pointer. A unique pointer only allows one variable and does not allow copying of that variable.
File: smart1.cpp
#include <iostream>
#include <memory>
#include <utility>
using namespace std;

//unique_ptr
class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};


int main()
{
    std::unique_ptr<student> valuePtr( new student(1) ) ;
    cout << "Student id:" << (*valuePtr).id << endl ;


}
The actual pointer is encapsulated in the object with the line:
std::unique_ptr valuePtr( new student(1) ) ;
When the object "valuePtr: goes out of scope then it will call a delete on the pointer. We can use the "make_unique" function to help create the pointer also.
File: smart2.cpp
#include <iostream>
#include <memory>
#include <utility>
using namespace std;

//unique_ptr
class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};

void function1( unique_ptr<student> ptr )
{


}

int main()
{
    std::unique_ptr<student> valuePtr( new student(1) ) ;
    cout << "Student id:" << (*valuePtr).id << endl ;


    //Compiler error . Cannot make
    //function1( valuePtr ) ;

    //Using the make_unique function
    std::unique_ptr<student> valuePtr1 = make_unique< student >(2) ;
    cout << "Student id:" << (*valuePtr1).id << endl ;
}
The "shared_ptr" allows us to make copies of the object. It keeps a referece count that is incremented every time the object is copied. That way the "delete" is only called once.
File: smart3.cpp
#include <iostream>
#include <memory>
#include <utility>
using namespace std;

//unique_ptr
class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};

void function1( shared_ptr<student> ptr )
{

  cout << "Inside function Reference count:" << ptr.use_count() << endl ;
}

int main()
{
    std::shared_ptr<student> valuePtr( new student(1) ) ;
    cout << "Student id:" << (*valuePtr).id << endl ;


    //
    cout << "Before function Reference count:" << valuePtr.use_count() << endl ;
    function1( valuePtr ) ;
    cout << "Outside function Reference count:" << valuePtr.use_count() << endl ;
    //Using the make_unique function
    shared_ptr<student> valuePtr1 = make_shared< student >(2) ;
    cout << "Student id:" << (*valuePtr1).id << endl ;

    //Reference countins is used so that the destructor is
    //called only once.
    shared_ptr<student> valuePtr2 = valuePtr ;
    cout << "Reference count:" << valuePtr2.use_count() << endl ;

    function1( valuePtr ) ;

}
We can use the "shared_ptr" in our vector example.
File: v5.cpp
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
//Use pointers to avoid a copy


class student
{
    public:
     int id  ;
     student( int idP )
      {
          id = idP ;
          cout << "Constructor called for  ;" << id << endl ;
      }
     student( const student& obj1 )
      {
          id = obj1.id ;
          cout << "Copy Constructor called for  ;" << id << endl ;
      }

     ~student(  )
      {
          cout << "Destructor called for  ;" << id << endl ;
      }

};



int main()
{

   // create a vector to store int
   vector< shared_ptr<student> > vec;

   {
     shared_ptr<student> valuePtr( new student(1) ) ;
     // display the original size of vec
     cout << "vector size = " << vec.size() << endl;
     // push 5 values into the vector
     vec.push_back( valuePtr );
     //valuePtr gets destroyed here but
     //delete is not called for valuePtr
   }

   cout << "value of vec [" << 0 << "] = " << vec[0]->id << endl;

   return 0;
}
There is nothing special about the smart pointer. It is a class that someone wrote. We can write our own simple smart pointer.
File: smart5.cpp
#include <iostream>

using namespace std ;

class Person
{
    int age;
    const char* pName;

    public:
        Person(): pName(0),age(0)
        {
        }
        Person(const char* pName, int age): pName(pName), age(age)
        {
        }
        ~Person()
        {
           cout << "Person Destructor." << endl ;
        }

        void Display()
        {
            printf("Name = %s Age = %d \n", pName, age);
        }
};

template < typename T > class SP
{
    private:
    T*    pData; // Generic pointer to be stored
    public:
    SP(T* pValue) : pData(pValue)
    {
    }
    ~SP()
    {
        delete pData;
    }

    T& operator* ()
    {
        return *pData;
    }

    T* operator-> ()
    {
        return pData;
    }
};

int main()
{
    SP< Person >   p(new Person("Scott", 25));
    p->Display();
    // Dont need to delete Person pointer..
    return 0 ;
}

List


File: list1.cpp
// C++ program to demonstrate the use of list containers
#include <iostream>
#include <list>
using namespace std;

int main()
{
    // defining list
    list<int> gqlist{12,45,8,6};
    //gqlist.insert( 1, 14, 1 ) ;
    for (auto i1 : gqlist)
    {
        cout << i1 << ' ';
    }

    //gqlist.
    list<int>::iterator it = gqlist.begin();
    advance(it, 2)  ;
    gqlist.insert( it, 1, 14 ) ;

    for (int i1 = 0; i1 < 2; ++i1 )
    {
        gqlist.push_back( i1 * 2 );
        gqlist.push_front( i1 * 3 );
    }
    cout << endl ;
    for (auto i1 : gqlist)
    {
        cout << i1 << ' ';
    }



    return 0;
}

Exercise


File: ex1.cpp
See the below links to help in the "showList" function. https://stackoverflow.com/questions/22874535/dependent-scope-need-typename-in-front
Solution

File: ex1s.cpp

Map


File: map1.cpp

File: map1.cpp

File: map1.cpp

Algorithms

This contains search, replace, sort algorithms.

An example of the sort function.
File: sort1.cpp

File: sort2.cpp
An example of the replace function.
File: replace1.cpp