Allocators

Encapsulates a memory allocation and deallocation strategy.
 
Every standard library component that may need to allocate or release storage, from std::string, std::vector, and every container except std::array, to std::shared_ptr and std::function, does so through an Allocator: an object of a class type that satisfies the following requirements.
 
Some requirements are optional: the template std::allocator_traits supplies the default implementations for all optional requirements, and all standard library containers and other allocator-aware classes access the allocator through std::allocator_traits, not directly.

Requirements :
Given :

  • A, an Allocator for type T
  • B, the same Allocator for type U
  • ptr, a value of type allocator_traits<A>::pointer, obtained by calling allocator_traits<A>::allocate()
  • cptr, a value of type allocator_traits<A>::const_pointer, obtained by conversion from ptr
  • vptr, a value of type allocator_traits<A>::void_pointer, obtained by conversion from ptr
  • cvptr, a value of type allocator_traits<A>::const_void_pointer, obtained by conversion from cptr or from vptr
  • xptr, a dereferencable pointer to some type X
Expression Requirements Return type
A::pointer (optional) Satisfies NullablePointer and RandomAccessIterator
A::const_pointer (optional) A::pointer is convertible to A::const_pointer. Satisfies NullablePointer and RandomAccessIterator
A::void_pointer (optional) A::pointer is convertible to A::void_pointer

B::void_pointer and A::void_pointer are the same type. Satisfies NullablePointer

A::const_void_pointer (optional) A::pointer, A::const_pointer, and A::void_pointer are convertible to A::const_void_pointer

B::const_void_pointer and A::const_void_pointer are the same type. Satisfies NullablePointer

A::value_type the type T
A::size_type (optional) A::size_type can represent the size of the largest object A can allocate unsigned integer type
A::difference_type (optional) A::difference_type can represent the difference of any two pointers to the objects allocated by A signed integer type
A::template rebind<U>::other (optional[1]) for any U, B::template rebind<T>::other is A the type B
*ptr T&
*cptr *cptr and *ptr identify the same object const T&
ptr->m same as (*ptr).m, if (*ptr).m is well-defined the type of T::m
cptr->m same as (*cptr).m, if (*cptr).m is well-defined the type of T::m
static_cast<A::pointer>(vptr) static_cast<A::pointer>(vptr) == ptr A::pointer
static_cast<A::const_pointer>(cvptr) static_cast<A::const_pointer>(vptr) == cptr A::const_pointer
a.allocate(n) allocates storage suitable for n objects of type T, but does not construct them. May throw exceptions. A::pointer
a.allocate(n, cptr) (optional) same as a.allocate(n), but may use cptr in unspecified manner to aid locality A::pointer
a.deallocate(ptr, n) deallocates storage previously allocated by a call to a.allocate(n). Does not call destructors, if any objects were constructed, they must be destroyed before calling a.deallocate(). Does not throw exceptions. (not used)
a.max_size() (optional) the largest value that can be passed to A::allocate() A::size_type
a1 == a2 returns true only if the storage allocated by the allocator a1 can be deallocated through a2. Establishes reflexive, symmetric, and transitive relationship. Does not throw exceptions. bool
a1 != a2 same as !(a1==a2) bool
A a1(a) Copy-constructs a1 such that a1 == a. Does not throw exceptions.
A a(b) Constructs a such that B(a)==b and A(b)==a. Does not throw exceptions.
A a1(std::move(a)) Constructs a1 such that it equals the prior value of a. Does not throw exceptions.
A a(std::move(b)) Constructs a such that it equals the prior value of A(b). Does not throw exceptions.
a.construct(xptr, args) (optional) Constructs an object of type X in previously-allocated storage at the address pointed to by xptr, using args as the constructor arguments
a.destroy(xptr) (optional) Destructs an object of type X pointed to by xptr, but does not deallocate any storage.
a.select_on_container_copy_construction() (optional) Provides an instance of A to be used by the container that is copy-constructed from the one that uses a currently. Usually returns either a copy of a or a default-constructed A(). A
a.propagate_on_container_copy_assignment (optional) true if the allocator of type A needs to be copied when the container that uses it is copy-assigned std::true_type or std::false_type or derived from such
a.propagate_on_container_move_assignment (optional) true if the allocator of type A needs to be copied when the container that uses it is move-assigned std::true_type or std::false_type or derived from such
a.propagate_on_container_swap (optional) true if the allocators of type A need to be swapped when two containers that use them are swapped std::true_type or std::false_type or derived from such

exception handling in c++

Exceptions provide a way to react to exceptional circumstances (like runtime errors) in our program by transferring control to special functions called handlers.
 
To catch exceptions we must place a portion of code under exception inspection. This is done by enclosing that portion of code in a try block. When an exceptional circumstance arises within that block, an exception is thrown that transfers the control to the exception handler. If no exception is thrown, the code continues normally and all handlers are ignored.
 
An exception is thrown by using the throw keyword from inside the try block. Exception handlers are declared with the keyword catch, which must be placed immediately after the try block:

Example

// A simple exception handling example.
#include <iostream>
using namespace std;

int main()
{
	cout << "Start\n";

	try
	{ // start a try block
		cout << "Inside try block\n";
		throw 100; // throw an error
		cout << "This will not execute";
	} catch (int i)
	{ // catch an error
		cout << "Caught an exception -- value is: ";
		cout << i << "\n";
	}

	cout << "End";

	return 0;
}

Class templates C++

Just as we can define function templates, we can also define class templates. The general form of a generic class declaration is shown here:

Syntax

template <class type> class class-name {
.
.
.
}

Example

#include <iostream>
using namespace std;

// template class declaration
template<class T> class MyClass
{
	T x, y;
public:
	MyClass(T a, T b) // constructor to initialize x,y with values
	{
		x = a;
		y = b;
	}
	T sum() // return of type T
	{
		return x + y; // returning sum
	}
};

int main()
{
	MyClass<int> forInteger(10, 3);
	cout << "integer sum: " << forInteger.sum() << "\n";

	MyClass<double> forDouble(10.6, 3.9);
	cout << "integer sum: " << forDouble.sum() << "\n";

	return 0;
}

Output

integer sum: 13
integer sum: 14.5

Templates in C++

Templates are a feature of the C++ programming language that allow functions and classes to operate with generic types. This allows a function or class to work on many different data types without being rewritten for each one.
 
Templates are of great utility to programmers in C++, especially when combined with multiple inheritance and operator overloading. The C++ Standard Library provides many useful functions within a framework of connected templates.
 
Templates are of two types :
1. Function templates
2. Class templates

1.Function templates

A function template behaves like a function except that the template can have arguments of many different types. See the following example for adding two generic numbers with the help of function templates :

#include <iostream>
using namespace std;

template<typename Type> // template declaration
Type gettingSum(Type a, Type b)
{
	return a + b; // will return sum
}

int main()
{
	cout << "for integers sum is  : " << gettingSum(2, 3) << endl;
	cout << "for floats sum is : " << gettingSum(2.3, 3.6);
	return 0;
}

Output of the above program is :

for integers sum is  : 5
for floats sum is : 5.9

regardless of any typecasting, redefining variables etc. This is how templates are very useful

generic programming

Generic programming is a style of computer programming in which algorithms are written in terms of to-be-specified-later types that are then instantiated when needed for specific types provided as parameters.
 
In very simple terms Generic programming is a type of programming in which we program without considering type of the functions and classes. This allows a function or class to work on many different data types without being rewritten for each one. Consider the following example for adding two integers:

for integers

#include <iostream>
using namespace std;

void gettingSum(int a, int b)
{
	cout << a + b; // will output sum as 5
}

int main()
{
	gettingSum(2, 3);
	return 0;
}

now the same program for float values

#include <iostream>
using namespace std;

void gettingSum(float a, float b)
{
	cout << a + b; // will output sum as 5.9
}

int main()
{
	gettingSum(2.3, 3.6);
	return 0;
}

Both of the above program has minor change from int values to the int values. But in order to evaluate the values of different types we have to write the whole program for some minor changes. This problem is solved by templates. Templates will be explained in next tutorial.

using at() with strings

C++ strings provide an alternative to the s[n] notation: the at( ) member. These two idioms produce the same result in C++.
There is an important difference is when you try to reference an array element that is out of bounds, at( ) will do you the kindness of throwing an exception, while ordinary [ ] subscripting syntax will be undefined behaviour. Example:

#include &lt;string&gt;
#include &lt;iostream&gt;
using namespace std;
int main()
{
    string s(&quot;123456789&quot;);
    // Runtime problem: goes beyond array bounds:
    cout &lt;&lt; s[5] &lt;&lt; endl;
    
    cout &lt;&lt; s.at(5) &lt;&lt; endl; // ok
    cout &lt;&lt; s.at(15) &lt;&lt; endl; // throw exception
    
    getchar();
    return 0;
}

comparing strings

C++ provides several ways to compare strings, and each has their advantages. The simplest to use are the non member overloaded operator functions operator ==, operator != operator >, operator <, operator >=, and operator <=. Example :

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    // Strings to compare
    string s1("This ");
    string s2("That ");
    
    for(int i = 0; i< s1.size() && i < s2.size(); i++)
    // See if the string elements are the same:
           if(s1[i] == s2[i])
           
    cout << s1[i] << " " << i << endl;
    // Use the string inequality operators
    if(s1 != s2) {
          cout << "Strings aren't the same:" << " ";
          if(s1 > s2)
          cout << "s1 is > s2" << endl;
          else
          cout << "s2 is > s1" << endl;
          }
    getchar();
    return 0;
}

detecting the occurrence of a sequence of characters in a string

The find member is also useful for detecting the occurrence of a sequence of characters in a string. Example :

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    string chooseOne("mango, tango, django, kolanglk");
    int i = chooseOne.find("go");
    
    while(i != string::npos) 
    {
            cout <<"found on " << i <<" position" << endl;
            i++;
            i = chooseOne.find("go", i);
    }
    getchar();
    return 0;
}

Output :

found on 3 position
found on 10 position
found on 18 position

finding strings position with find()

Searches a string for a specified character or group of characters and returns the starting position of the first occurrence found or -1 if no match is found.

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    string s1("Humpty ");
    
    // find returns the first character position in any string
    cout << s1.find('m') << endl; // will return 2
    
    getchar();
    return 0;
}

Searching in strings

The various functions that are being used to search strings are as follows :

string find function What/how it finds
find( ) Searches a string for a specified character or group of characters and returns the starting position of the first occurrence found or npos if no match is found. (npos is a const of –1 and indicates that a search failed.)
find_first_of( ) Searches a target string and returns the position of the first match of any haracter in a specified group. If no match is found, it returns npos.
find_last_of( ) Searches a target string and returns the position of the last match of any character in a specified group. If no match is found, it returns npos.
find_first_not_of( ) Searches a target string and returns the position of the first element that doesn’t match any character in a specified group. If no such element is found, it returns npos.
find_last_not_of( ) Searches a target string and returns the position of the element with the largest
subscript that doesn’t match of any character in a specified group. If no such element is found, it returns npos.
rfind( ) Searches a string from end to beginning for a specified character or group of characters and returns the starting position of the match if one is found. If no match is found, it returns npos.

may of them are explained in later pages.

string concatenation with +

One of the most delightful discoveries awaiting a C programmer learning about C++ string handling is how simply strings can be combined and appended using operator+ and
operator+=. These operators make combining strings syntactically equivalent to adding numeric data. Example :

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    string s1("Humpty ");
    string s2("Dumpty ");
    string s3(", then what i do ? ");
    
    // operator+ concatenates strings
    s1 = s1 + s2;
    
    cout << s1 << endl;
    // Another way to concatenates strings
    s1 += s3;
    cout << s1 << endl;
    
    // You can index the string on the right
    s1 += s3 + s3[4] + "hahaha";
    cout << s1 << endl;
    
    getchar();
    return 0;
}

concat, substring strings

Consider the following example for various operations on strings

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    string s1("this string represents s1");
    string s2("All mangoes are bananas");
    string s3("snow is the purest form of water");
    
    // Copy the first 8 chars from s1 in string s4
    // string s4(<string>, <starting index>, <end index>);
    string s4(s1, 0, 8);
    
    //appending strings
    string s5 = string (s1, 0, 4) + " helllo " +
                 string (s3, 0, 8);
                 
    // finding substring 
    //s3.substr(<from starting index>, <upto index>)
    string s6 = s3.substr(5, 10);
    
    string s7 = s3.substr(1, 5) + s5;
        
    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    cout << s4 << endl;
    cout << s5 << endl;
    cout << s6 << endl;
    cout << s7 << endl;
    
    getchar();
    return 0;
}

Creating and initializing C++ strings

Creating and initializing strings is a straightforward proposition, and fairly flexible as well. In the example shown below :
 
the first string, blankString, is declared but contains no initial value. Unlike a C char array, which would contain a random and meaningless bit pattern until initialization, imBlank does contain meaningful information. This string object has been initialized to hold “no characters,” and can properly report its 0 length and absence of data elements through the use of class member functions.
 
The next string, secondString, is initialized by the literal argument “this is second string”. This form of initialization uses a quoted character array as a parameter to the string constructor
 
thirdString is simply initialized with an assignment.
 
fourthString, is initialized using an existing C++ string object. Put another way, this example illustrates that string objects let you:
 
1.Create an empty string and defer initializing it with character data
2.Initialize a string by passing a literal, quoted character array as an argument to the constructor
3.Initialize a string using ‘=‘
4.Use one string to initialize another

Example

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    // A blank string
    string blankString;
    
    // another way of initializing string
    string secondString("this is second string");
    
    
    // example of multiline string
    string thirdString = "this is multiline string "
    "and this is third one";
    
    // declaring while copying strings
    string fourthString(secondString);
    
    // A way to initialize string of size 20 with all 'A' characters
    string fifthString(30,'A');


    cout << "blankString = " << blankString << endl;
    cout << "secondString = " << secondString << endl;
    cout << "thirdString = " << thirdString << endl;
    cout << "fourthString = " << fourthString << endl;
    cout << "fifthString = " << fifthString << endl;
    
    getchar();
    return 0;
}

strings intro

First, C++ string objects associate the array of characters which constitute the string with methods useful for managing and operating on it, a C++ string object knows its starting location in memory, its content, its length in characters, and the length in characters to which it can grow before the string object must resize its internal data buffer.
 

difference between C char arrays and C++ strings. C++ strings do not include a null terminator, nor do the C++ string handling member functions rely on the existence of a null terminator to perform their jobs. C++ strings greatly reduce the likelihood of making three of the most common and destructive C programming errors:
1.overwriting array bounds
2. trying to access arrays through uninitialized or incorrectly valued pointers,
3. and leaving pointers “dangling” after an array ceases to occupy the storage that was once allocated to it.

Example :

#include <string>
#include <iostream>
using namespace std;
int main() 
{
    string s1("12345");
    string s2 = s1; // copy of string s1
    
    cout << "s1 = " << s1 << endl;
    cout << "s2 = " << s2 << endl;
    getchar();
    return 0;
}