Namespaces and STL.

A programming project of an average size includes a number of standard header files (such as iostrem, math, winsock, etc) and a list of header files created by the programmer. Each of these files usually has a big number identifiers defined in it. Thus, the total number of identifiers used in a project can be huge even for not big projects. A programmer isn't usually aware of all identifiers declared in standard header files. This creates a considerable risk that two different items declared in separate files will be given the same name and (which is even worse) different values. For example, we can easily use identifiers like size, type, or object. This is very annoying to look for errors like this in a program code, especially if the project was successfully compiled just a minute ago and after including one more header file it produces a list of errors, and now you need to replace your identifier object_size to something less popular in all 27 project files . A new C++ construct offers a solution for this problem. This construct is called name space.

We can enclose a group of declarations inside a name space, and these declarations will be visible only inside the name space. To make these objects visible from outside the name space we need to use syntax like

namespace_name::identifier

Defining and using a name space

To create a new name space, we use the following syntax:
namespace name {
   declarations;
}
For example, we can create a new name space RobotWar and define several classes like Object, Location, Robot in it:
// File: robot.h

namespace RobotWar {
   class Object {
      public: ...
      private: ...
   };

   class Location {
      public: ...
      private: ...
   };

   class Robot : public Object {
      public: ...
      private:
         Location coord;
   };

   double Distance(const Location &one, const Location &two);

} // end of the name space

Now, we don't need to worry that some of these identifiers are used in standard libraries (Object, for example). Inside our program we can use them like:

#include "robot.h"

void main()
{
RoborWar::Location point(5, 15);
... }
But if we try to define an object of the Location type without prefix RobotWar, we'll get an error message because the identifier location is not defined outside of the name space RobotWar:
   5:   Location point(5, 45);
error C2065: 'Location' : undeclared identifier

We can also define objects with the same identifiers inside a different name space and there will be no conflict between them:

namespace RobotPeace {
   class Robot {
      ...
   };
}
Using the right name space we can declare exactly the object we want:
RobotWar::Robot tank;
RobotPeace::Robot taxi;

We can use the same name space in different header files. In this case, the first appearance of the name space is considered by the compiler as the definition of the name space, and others are considered as extensions of the name space. We can also provide an alternative name for a name space. The syntax for creating an name space alias is:

namespace alias = namespace_name;
For example, to create an alias RW for the name space RobotWar we need to write
namespace RW = RobotWar;
After this line we can access the identifiers inside this name space as RW::Distance().

The namespace keyword may appear inside another name spaces. That is, we are allowed to created nested name spaces. For example, if we want to create a lot of objects for robots, but also we would like to separate war robots from peace robots we can do something like this:

// File: robot.h

namespace Robots {
   class Object {
      ...
   };

   class Location {
      ...
   };

   namespace War {
      class Robot : public Object {
         ...
      };
   } // end of the War name space

   namespace Peace {
      class Robot : public Object {
         ...
      };
   }  // end of the Peace name space


} // end of the name space Robot

namespace RW = Robots::War;
namespace RP = Robots::Peace;
In this case, to declare an object of the type Robot we need to use the prefix that contains two name spaces, for example,
Robots::War::Robot   tank;
Robots::Peace::Robot taxi;

So far, to refer to an identifier declared inside a name space we were using the explicit declaration. Another way to refer to these identifiers, is to use the using directive. This directive allows to make one identifier from a name space visible. For example, we can use it in the form like

#include "robot.h"

using Robots::War::Robot; // make the definition of the class Robot visible in this program
void main() { Robot tank; Robots::Peace::Robot taxi; ... }
The same directive can make all identifiers in a name space visible for a program. The syntax for this is
using namespace namespace_name;
For example, we can make all identifiers in the Robots name space visible by using
using namespace Robots;
After this declarations we cam define objects of the Location without using any prefix and objects of the Robot type only with one proper prefix:
using namespace Robots;
...
Location point;
War::Robot tank;
Of course, we can use several using directives in program. Be careful, though. If we decide to use both:
using namespace Robots::War;
using namespace Robots::Peace;
and then try to define a new object of the Robot class without specifying which robot we mean, we'll end up having an error message:
 7: Robot tank;
ns.cpp(31) : error C2872: 'Robot' : ambiguous symbol
        could be 'ns.cpp(19) : Robots::Peace::Robot'
        or       'ns.cpp(15) : Robots::War::Robot'

Predefined name spaces

MS Visual Studio contains many predefined classes grouped into name spaces. Some of the most popular name spaces are in the table below, the complete list of the predefined name spaces can be found in the MSDN library.
Name space Description
System Contains fundamental classes and base classes that define commonly used value and reference data types, events and event handlers, interfaces, attributes, and processing exceptions.
Other classes provide services supporting data type conversion, method parameter manipulation, mathematics, remote and local program invocation, application environment management, and supervision of managed and unmanaged applications.
System.Collections Contains interfaces and classes that define various collections of objects, such as lists, queues, bit arrays, hashtables and dictionaries.
System::Data Consists mostly of the classes that constitute the ADO.NET architecture. The ADO.NET architecture enables you to build components that efficiently manage data from multiple data sources. In a disconnected scenario (such as the Internet), ADO.NET provides the tools to request, update, and reconcile data in multiple tier systems. The ADO.NET architecture is also implemented in client applications, such as Windows Forms, or HTML pages created by ASP.NET.
System::Data::SqlClient Encapsulates the .NET Framework Data Provider for SQL Server. The .NET Framework Data Provider for SQL Server describes a collection of classes used to access a SQL Server database in the managed space.
System::Drawing Provides access to GDI+ basic graphics functionality. More advanced functionality is provided in the System::Drawing::Drawing2D, System::Drawing::Imaging, and System::Drawing::Text namespaces.
System::Drawing::Drawing2D Provides advanced 2-dimensional and vector graphics functionality. This namespace includes the gradient brushes, the Matrix class (used to define geometric transforms), and the GraphicsPath class.
System::Drawing::Imaging Provides advanced GDI+ imaging functionality. Basic graphics functionality is provided by the System::Drawing namespace.
System::Drawing::Text Provides advanced GDI+ typography functionality. Basic graphics functionality is provided by the System::Drawing namespace. The classes in this namespace allow users to create and use collections of fonts.
System::IO Contains types that allow synchronous and asynchronous reading and writing on data streams and files.
System::Net Provides a simple programming interface for many of the protocols used on networks today. The WebRequest and WebResponse classes form the basis of what are called pluggable protocols, an implementation of network services that enables you to develop applications that use Internet resources without worrying about the specific details of the individual protocols.
System::Security Provides the underlying structure of the .NET Framework security system, including base classes for permissions.
System::Timers Provides the Timer component, which allows you to raise an event on a specified interval.
System::Web Supplies classes and interfaces that enable browser-server communication. This namespace includes the HTTPRequest class that provides extensive information about the current HTTP request, the HTTPResponse class that manages HTTP output to the client, and the HTTPServerUtility object that provides access to server-side utilities and processes. System.Web also includes classes for cookie manipulation, file transfer, exception information, and output cache control.
System::Windows::Forms Contains classes for creating Windows-based applications that take full advantage of the rich user interface features available in the Microsoft Windows operating system.
System::Xml Provides standards-based support for processing XML.

std name space and Standard Template Library

Another standard name space is the std. This name space includes all C++ standard library identifiers such as cout, cin, cos(), etc. The usage of this name space is declared inside all standard C++ header (.h) files. Thus, if we use
#include <iostream.h>
we do not need to explicitly state that we use the std name space. In other words, we don't need to have
using namespace std;
However, if we use header files without the .h extension, we do need to specify a name space explicitly:
#include <iostream>
using namespace std;

The std name space among other things contains the Standard Template Library (STL) that provides tools to work with different type of containers and a list of algorithms to work with these containers. The STL template container classes are:

In this course we will not discuss all of possibilities the STL gives the programmer, but we will shortly discuss vectors and queues.

Class vector

Template class vector provides a sequential storage for elements of any given type. The size of the array grows and shrinks as needed. To create an array of element of the type, let's say int we need to do this:
vector<int> arr;
It's commonly not to specify the size of the storage because it grows or shrinks depending on the program needs, however, it can be done:
vector<int> arr(100);
This class provides an access to each element of the new array by index. For example, we can now access the first element of the array as arr[0]. Some member functions of this class are
Method Description
back() Returns a reference to the last element of the vector.
begin() Returns a random-access iterator to the first element in the container.
capacity() Returns the number of elements that the vector could contain without allocating more storage.
clear() Erases the elements of the vector.
empty() Tests if the vector container is empty.
end() Returns a random-access iterator that points just beyond the end of the vector.
erase(where)
erase(first, last)
Removes an element or a range of elements in a vector from specified positions. The parameters are:
  • where - iterator pointing at position of the element to be removed from the vector.
  • first - iterator pointing at position of the first element removed from the vector.
  • last - iterator pointing at position just beyond the last element removed from the vector.
As a return value the method returns an iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the vector if no such element exists.
front() Returns a reference to the first element in a vector.
insert(where, value)
insert(where, count, value)
Inserts an element or a number of elements into the vector at a specified position. The parameters are:
  • where - The position in the vector where the first element is inserted.
  • value - The value of the element being inserted into the vector.
  • count - The number of elements being inserted into the vector.
max_size() Returns the maximum length of the vector.
pop_back() Deletes the element at the end of the vector.
push_back(value) Adds an element to the end of the vector.
size() Returns the number of elements in the vector.
Some public methods of the vector class.
Here is a small example that shows how to deal with the vector.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

void main()
{
   int i, j;
   vector<int> v;

   for(i=0;i<15;i++){
      j = rand() % 20;
      v.insert(v.end(), j);
      cout<<"Inserted new element "<<j<<" into the array\n";
   }

   sort(v.begin(), v.end());

   cout<<"\nAfter sorting teh array is:\n";
   for(i=0;i<v.size();i++)
      cout<<v[i]<<" ";
}
Note: do not forget to include the vector header file.

Class deque

The deque class provides a tool for implementing an array with efficient insertions/deletions at either end. This class is defined in the header file deque (or deque.h), so don't forget to include it. The following table contains some public methods of the deque class.
Method Description
back() Returns a reference to the last element of the deque.
begin() Returns a random-access iterator to the first element in the deque.
capacity() Returns the number of elements that the vector could contain without allocating more storage.
clear() Erases the elements of the deque.
empty() Tests if the deque container is empty.
end() Returns an iterator that addresses the location succeeding the last element in a deque.
erase(where)
erase(first, last)
Removes an element or a range of elements in a deque from specified positions. The parameters are:
  • where - iterator pointing at position of the element to be removed from the vector.
  • first - iterator pointing at position of the first element removed from the vector.
  • last - iterator pointing at position just beyond the last element removed from the vector.
As a return value the method returns an iterator that designates the first element remaining beyond any elements removed, or a pointer to the end of the vector if no such element exists.
front() Returns a reference to the first element in a deque.
insert(where, value)
insert(where, count, value)
Inserts an element or a number of elements or a range of elements into the deque at a specified position. The parameters are:
  • where - The position in the deque where the first element is inserted.
  • value - The value of the element being inserted into the deque.
  • count - The number of elements being inserted into the deque.
max_size() Returns the maximum length of the deque.
pop_back() Deletes the element at the end of the deque.
pop_front() Deletes the element at the beginning of the deque.
push_back(value) Adds an element to the end of the deque.
push_front(value) Adds an element to the beginning of the deque.
size() Returns the number of elements in the deque.
Some public methods of the deque class.
The following example shows how to use a deque container as a priority queue:
#include <iostream>
#include <deque>
#include <algorithm>
using namespace std;

void main()
{
   int i, j;
   deque pq;

   for(i=0;i<15;i++){
      j = rand() % 25;
      pq.push_back(j);
      cout<<"Inserted new element "<<j<<" into the array\n";
   }

   sort(pq.begin(), pq.end());

   cout<<"\nAfter sorting the deque is:\n";
   while( ! pq.empty() ){
      j = pq.front();
      cout<<j<<" ";
      pq.pop_front();
   }
}
Please find the advanced deque example on the example page.

STL algorithms

As you probably noticed in both our examples we used the algorithm header file. This file contains a number of functions that perform different operations against STL containers. We even used one of these function - the sort() function. The complete list of these functions can be found in the MSDN Libarry or in the MS Visual Studio documentation under STL algorithms. Some of the functions are in the table below:
Method Description
adjacent_find() Searches for two adjacent elements that are either equal or satisfy a specified condition.
binary_search() Tests whether there is an element in a sorted range that is equal to a specified value or that is equivalent to it in a sense specified by a binary predicate.
copy() Assigns the values of elements from a source range to a destination range, iterating through the source sequence of elements and assigning them new positions in a forward direction.
count() Returns the number of elements in a range whose values match a specified value.
count_if() Returns the number of elements in a range whose values match a specified condition.
find() Locates the position of the first occurrence of an element in a range that has a specified value.
find_end() Looks in a range for the last subsequence that is identical to a specified sequence or that is equivalent in a sense specified by a binary predicate.
find_first_of() Searches for the first occurrence of any of several values within a target range or for the first occurrence of any of several elements that are equivalent in a sense specified by a binary predicate to a specified set of the elements.
for_each() Applies a specified function object to each element in a forward order within a range and returns the function object.
includes() Tests whether one sorted range contains all the elements contained in a second sorted range, where the ordering or equivalence criterion between elements may be specified by a binary predicate.
lower_bound() Finds the position of the first element in an ordered range that has a value less than or equivalent to a specified value, where the ordering criterion may be specified by a binary predicate.
max_element() Finds the first occurrence of largest element in a specified range where the ordering criterion may be specified by a binary predicate.
min_element() Finds the first occurrence of smallest element in a specified range where the ordering criterion may be specified by a binary predicate.
nth_element() Partitions a range of elements, correctly locating the nth element of the sequence in the range so that all the elements in front of it are less than or equal to it and all the elements that follow it in the sequence are greater than or equal to it.
pop_heap() Removes the largest element from the front of a heap to the next-to-last position in the range and then forms a new heap from the remaining elements.
push_heap() Adds an element that is at the end of a range to an existing heap consisting of the prior elements in the range.
replace() Examines each element in a range and replaces it if it matches a specified value.
reverse() Reverses the order of the elements within a range.
search() Searches for the first occurrence of a sequence within a target range whose elements are equal to those in a given sequence of elements or whose elements are equivalent in a sense specified by a binary predicate to the elements in the given sequence.
search_n() Searches for the first subsequence in a range that of a specified number of elements having a particular value or a relation to that value as specified by a binary predicate.
sort() Arranges the elements in a specified range into a nondescending order or according to an ordering criterion specified by a binary predicate.
unique() Removes duplicate elements that are adjacent to each other in a specified range.
upper_bound() Finds the position of the first element in an ordered range that has a value that is greater than a specified value, where the ordering criterion may be specified by a binary predicate.
Some algorithms implemented in the algorithm.h.

Iterators

Most often elements of STL containers are accessed through iterators. Iterators are special data members (objects) that can iterate containers. Every iterator object represents a position in a container. We can think of an iterator as a pointer to a particular element of a container. In fact, in some cases iterators are just pointers. The advantage of iterators is that they allow all containers to provide the same interface for accessing their elements. Please note that although we can think of iterators as pointers, they actually are not. They are objects of special iterator class. More over, the exact iterator type depends on the container it iterates through. Thus, do declare an object of iterator type we need to use the following syntax:
container_type<object_type>::iterator iterator_obj_name;
For example, to declare an iterator for iterating a vector if integers we need to type
vector<int>::iterator pos;
and to declare an iterator for a queue of Robots we need to use
deque<Robot>::iterator cur_pos;

Container classes have methods that work with iterators. The two probably most important ones are

begin() and end() iterators.
A typical way to iterate through a container's elements is:
vector<int> v;
vector<int>::iterator pos;
for(pos=v.begin(); pos!=v.end(); pos++ )
   cout<<*pos<<endl;
As you can see we used operators !=, ++, and * applied to the iterator variable. Operator != compares two iterators and returns true if they point to different elements of a container (here we are talking about actual elements, net their values). Also there is operator == that does completely the opposite; that is, returns true if the iterators point to the same element.

The ++ operator advanced an iterator to the next element of the container. Bidirectional iterators also have a similar operator -- that moves the iterator to the previous element. The * operator is used to access the element the iterator refers to. For example, *pos is an integer value from the array v in the example above.

random-access iterators (provided by vector and deque containers) also support operator + in the form

iterator + n
where n is an integer. In this case, pos+n references the next nth value following the iterator. Random-access iterators can also compute the difference between two iterators. This difference is the number of elements between two iterators.