Saturday, January 11, 2014

Chapter:07 Lambda Expression

From the name 'lambda', we all remember our high school mathematics. I believe there must be a valid relation between these two, due to which the names are identical. If we read about 'lambda' on wikipedia we get the following:

"Lambda calculus  is a formal system in mathematical logic and computer science for expressing computation based on 'function' abstraction and application using variable 'binding' and 'substitution'".


This is precisely lambda function concept in C++11 does for us. These are also known as anonymous functions as these are not bind to a particular name. They can be  directly written at the place where we normally user/write 'functor' object.  I do not know what sort of benefits user would get if he uses lambda function instead of 'functor' object. Sometime we need to write a small 'functor' for which we need to write a class for that and inside that define 'operator()' which actually does the work for us.


These steps might be bit more for small 'functor' like functionality. In those cases we can use lambda function at the place where it would be used. Baring this I do not find any other advantages of lambda over 'functor' as 'functor' are one of the most optimized piece of code in entire STL. In fact they are easily inlined by compiler and hence they even do not have the cost of a function call. Anyway I think 'lambda' as another method over 'functor'  and we can interchange their usage with each other. As I have mentioned that  it is always good to know more than one method to address the same problem.
This kind of concepts supports this philosophy



The current program uses two lambda function. At first place we have written lambda function for the adding all members of a container. The key over here is syntax and I found it bit difficult to understand. However in simple scenario, if we want that lambda function return some output after it has executed for all  member of container, we should pass those variable inside '[ ]' body of lambda function. The main body would be inside the curly  braces and input argument would be passed inside '( )'. This is how it has been used in this program at both the places.


The second lambda function returns the number of elements which are less  than a particular value(3). Here we can see how we have passed two argument in the lambda. We should also notice that how code inside the lambda function has been written. It looks same as if we have written a function.



//Code Begins

#include<iostream>
#include<vector>
#include<algorithm>

void learn_lambda_expression(void) {
    std::vector<int> v_x{1,2,3,4,5};
    int sum{0};

    std::for_each(v_x.begin(), v_x.end(),
            [&sum](int x) { sum += x; return sum;});

    std::cout<<sum<<std::endl;

    std::vector<int> v_y{6,6,6,3,6,5,3};
    int count{0};
    int val{3};

    std::count_if(v_y.begin(), v_y.end(),
            [&count,&val](int x) {if(x == val) {++count; return true; }});

    std::cout<<count<<std::endl;
}

int main(int argc, const char* argv[]) {
    learn_lambda_expression();
    return 0;
}

//Code Ends



When I run the above program, I get the following output which was expected.



//Console Output Begins
$ ./test
15
2
//Console Output Ends



This is another example of where lambda function uses has been demonstrated. Here we want to store the elements which are less than a particular value(3) into another container. This lambda  function is similar to earlier one in our first example. Here  we have written the body for 'if' and 'else' part. At first part in the  program, we have defined a container of size same as the input container. Now 'copy if' STL algorithm would actually insert those members  which are greater than(3).


Once we are done with 'copy if' STL algorithm, we have the count of elements which are greater than (3). Now we can make use of that information and shrink our output vector to that much size. At last we have printed the output container members which stores the memebers which are greater than(3).




//Code Begins

#include<iostream>
#include<vector>
#include<algorithm>

void learn_lambda_expression(void) {
    std::vector<int> v_y{6,5,4,3,2,1,3,9};
    int val{3};
    std::vector<int> l_y(v_y.size());
    int count{0};

    std::copy_if(v_y.begin(), v_y.end(), l_y.begin(),
            [&val,&count](int x) {if(x > val)
            {++count; return true; }else {return false;}});

    l_y.resize(count);

    for(const auto& i: l_y)
        std::cout<<i<<"\t";
    std::cout<<std::endl;
}

int main(int argc, const char* argv[]) {
    learn_lambda_expression();
    return 0;
}

//Code Ends





When I run the above program, I get the following output.


//Console Output Begins
$ ./test
6    5    4    9   
//Console Output Ends


Chapter:07 Supress/Allow Methods

Fundamental
========

In older C++ standard, if we want to disallow client code to use a particular method of a class, we used to define it as 'private' member. This way we can prevent these functions gets called by external client code, but what about the other class functions. I mean by defining as 'private' we can not restrict any other class functions to use their own private functions.


In addition to that if you have written parametrized constructor, then if user code would try to use the default constructor, there would be compilation error. Many time we want to write parametrized constructors and also want to use the  default constructor and related functions which manages class resources. To achieve this we had to write the default constructor of our own. This may lead to some problem in future if we add the new members in this class we had to modify all constructors. There are chances of mistake if we miss out something.


Also if we can not write better code for a particular thing, we better should rely on the default implementation provided by system. Those would be almost most optimized and safer solution in longer term.


C++11 has introduced the concept to allow to 'delete' that particular function. By this mechanism we can prevent any uses of these functions, whether its other class member functions or any client code. For second problem, C++11 has introduced the concept of 'default'. So if you want to make use of default version of the 6 functions(which manages the class resources), you can just mention 'default' and  you would be able to use these default along with your own parametrized constructors and other related functions. These concept along with the in class initializer we  can write very clean and beautiful code for these 6 resource managing functions of a class. I would cover in-class initializer feature in the later chapter.




Uses
===

The current sample program demonstrates that with the use of 'default/delete'  and 'in-class initializer', we can write very elegant code. Here I have defined a parametrized constructor, and also I have enabled the 'default' version of  constructor and destructor. And using in-class initializer, I have made those two variables to be zero. So if client code creates the object of this class with out providing any argument, the default version of constructor would be called. We all know that if we do not enable default version, then there would be compilation error if we do not write our own version.


These things were even possible prior to C++11 as we could have used the parametrized constructor with default values which would have taken care
this situation. But I think that it looks good and clearly distinguish the user version from the default generated version of these 6 functions. I guess even system can make use of this and our code might provide better performance as system can do all sort of tweak and twist to optimize it. I like the C++11 version solution for these instead of older. Hope it make sense to all of us.



//Code Begins

#include<iostream>
class x {
public:
    x(int a, int b):aa(a),bb(b){}
    ~x()=default;
    x()=default;
    void display_element(void) {
        std::cout<<aa<<"\t"<<bb<<std::endl;
    }
private:
    int aa{0};
    int bb{0};
};

void learn_default_allow(void){
    x o_x;
    o_x.display_element();
}

int main(int argc, const char* argv[]) {
    learn_default_allow();
    return 0;
}
//Code Ends



When I run the above program, I get the following output. This was expected and program looks good and elegent.



//Console Output Begins
$ ./test
0    0
//Console Output Ends





We can 'delete' any function of a class. Unlike 'default' which is only applicable to the 6 functions which gets generated by compiler, 'delete' can be used for any memeber function of a class. It is also possible to delete partially for generic function. Here partial means you can allow the same function to gets called for a particular set of arguments and 'delete' for a the rest of the argument. There is no magic behind  this, as we know that compiler generates a unique functions(as if it was hand written) for a particular type of arguments. So in a way  ,there would be different functions loaded when we call the generic function for a particular type of argument. So this is same as if we have called 'delete' for a particular generic function for specified type of arguments.


The current program contains a polymorphic type of class as it has virtual functions. Consider a  scenario, where we define an abstract class(which has at least one pure virtual function). This abstract class has implemented some functions so in a way its not complete abstract type. Normally  these classes would be inherited  by some new class where we would implement the remaining functions which has not been defined in base abstract class. This way C++ supports the incremental design philosophy.


However there seems to be bit problem in the above approach. What if user want to use and test the abstract class at first place itself. I mean after all, if someone want to use and test the existing implemented functionality of that particular abstract class, it would be great I guess. Again this was possible even in older C++ standard where we would simply write blank body of that class so that user would be able to create the object of that particular class.


Here I present a different approach to do the same thing. We can actually 'delete' those functions which has not been  implemented in that particular class. Once we are done with our local testing we can remove the 'delete' from these functions. By this approach also we can create the object  of such class. Here I do not claim that this is correct approach or this approach has some advantages over conventional one. This is just a different one. I always believe that  its always advantageous to know more than one approach to address the same problem.



//Code Begins

#include<iostream>
class y {
public:
    y(int a, int b):aa(a),bb(b){}
    virtual ~y()=default;
    y()=default;
    int add_number(){
        int tmp{};
        tmp=aa+bb;
        return tmp;
    }
    virtual int multiply_number()= delete;
    /* virtual int multiply_number()= 0; */
private:
    int aa{10};
    int bb{20};
};


void learn_default_allow(void){
    y o_y;
    auto res_add = o_y.add_number();
    /* auto res_mult = o_y.multiply_number(); */
    std::cout<<res_mult<<std::endl;
}

int main(int argc, const char* argv[]) {
    learn_default_allow();
    return 0;
}

//Code Ends



When I run the above program, I get the following output. This was expected as we have learned in above discussion.


//Console Output Begins
$ ./test
30
//Console Output Ends




If we go by conventional approach and  comment the 'delete' function and uncomment the two line which I have commented in the above code. By this way if user would like to use this class, compiler would not  be able to create the object as it has one 'pure' virtual function. Here we can not do any uses/testing for this class.




//Console Output Begins
$ g++ -g -gdwarf-2 -std=c++11 -Wall test_2.cpp -o test_2
test_2.cpp: In function ‘void learn_default_allow()’:
test_2.cpp:20:4: error: cannot declare variable ‘o_y’
to be of abstract type ‘y’
  y o_y;
    ^
test_2.cpp:2:7: note:   because the following virtual functions
are pure within ‘y’:
 class y {
       ^
test_2.cpp:13:16: note:     virtual int y::multiply_number()
    virtual int multiply_number()= 0;
                ^
//Console Output Ends




Chapter:06 Move Constructor

Fundamental
========

'move' constructor mechanism is one of the main core language feature introduced in C++11. As we all know that 'class' is the most key concept in C++ and 'move'  constructor is sort of directly associated with the the 'class' concept. Thats the reason I think its very important core language feature introduced. 'move' basically avoids the unnecessary making of copy of object,as many times it happens that there is no real usage of original copy of the object and copy was useless. So instead of the copy we can move the resource. By this way it avoid the scenario where multiple objects points to same resource. It does all those by simply moving the resource. Please be patient if someone has some confusion on these, I guess by the end of this chapter you would get what it all means.


I was watching one of Bjarne Stroustrup speech, he actually mentioned about this concept."When we need to put some object from our one hand to other, we simply move the object and its done. Even the 2-3 year kids know this however only stupid computer scientists would actually make a copy of that object and then move from one hand to other.”


The above lines says simple philosophy, do not complicate the things which can be done in simpler manner. And we can learn many things and apply in any field even from a kid. I have mentioned that this change directly impacts the core 'class' concept. Hence there are some fundamental changes which we need to know to really make use of this concept. Prior to C++11 standard, there were mainly 4 functions which managed the resource handling for a class. Now there are 2 additional functions which are introduced to support the 'move' mechanism.


1. Default Constructor.
2. Destructor.
3. Copy Constructor.
4. Assignment Operator.
5. Move Constructor.
6. Move Assignment Operator.


There are some rules which govern, when compilers would generate all 6 functions and its bit complicated. The simple rule is define all 6 whenever you have defined your own version for any of these. Otherwise default version of these functions, generated by compiler would be sufficient for us. Here I have not mention those rules as those are bit complicated,if you are interested please refer to books  which I have mentioned in this article. However important point over here is if you write these 6 functions with proper thinking and RAII concept, you do not have to worry about many things. Now you can pass any class object by value to any other function without worrying efficiency and safety. As usual we should pass any class by reference to any function while passing as argument.



In current program, I have written a simple class with all 6 functions. In addition to that I have put the appropriate message in each of these functions so that we can understand when these functions called.  The program is self explanatory and  reader should be able to get this. If anyone finds it difficult, I urge them to devote the time until they get this concept completely.



While understanding this new concept, keep one thing in mind that all previous concepts are still valid except for a couple of changes. Now if your program is returning any class object by value, the move assignment operator would execute. Sometime compiler would not be able to think as smart as we can. I mean if we know that there will not be any further usage of that particular objects and we want to make a copy of that, we  should call 'std::move()', which always calls move constructor if it is defined for that particular class. Otherwise copy constructor like old days concept would get  called under these situation.



//Code Begins

#include<iostream>

template<typename T>
void display(const T& val) {
    std::cout<<val<<std::endl;
}

class x {
public:
    x() {
        display("x::x(), default constructor");
    }

    ~x() {
        display("x::~x(), destructor");
    }

    x(const x& rhs) {
        display("x::x(const x&), copy constructor");
    }

    x& operator=(const x& rhs) {
        display("x::operator=(const x& rhs), assignment operator");
    }

    x(x&& rhs) {
        display("x::x(&& rhs), move constructor");
    }

    x& operator=(x&& rhs) {
        display("x::operator=(x&& rhs), move assignment operator");
    }
};


x function(void) {
    x o_c;
    return o_c;
}

void learn_move_constructor(void) {
    x o_a;
    x o_b(o_a);

    o_b = o_a;
    x o_d;
    o_d = function();
    x o_e = std::move(o_d);
}


int main(int argc, const char* argv[]) {
    learn_move_constructor();
    return 0;
}

//Code Ends



When I run the above program,I get the following output. If we watch them carefully or put the breakpoint on all these 6 functions under gdb and study the stack trace, we can understand them completely.



//Console Output Begins

$ ./test
x::x(), default constructor
x::x(const x&), copy constructor
x::operator=(const x& rhs), assignment operator
x::x(), default constructor
x::x(), default constructor
x::operator=(x&& rhs), move assignment operator
x::~x(), destructor
x::x(&& rhs), move constructor
x::~x(), destructor
x::~x(), destructor
x::~x(), destructor
x::~x(), destructor

//Console Output Ends




Implementation
==========

The previous section was sort of net practice before the actual match. The following examples demonstrate the real implementation and key concepts of
'move' semantics. We have discussed in the previous example that 'move' actually move the resource pointer from left side object of assignment to  right side, as left side object would no longer be used once we go out of the scope of that particular function. However we know that whenever any objects go out of scope, its destructor gets called. So at this point the left side object state should be such that it destructor could execute successfully.


'move' constructor basically achieves this by doing pointer like assignment for moving resource from one object to other. Once its done it also resets the left side object pointer to the default values like 'nullptr' or 0 whereever  appropriate. By this destructor gets called for the left side object when going out of scope correctly as objects invariants are in valid state. All actual resource would be transferred to right side object in the assignment. This is the key concept in 'move'.


We need to pass the argument by 'reference' not by 'const reference' as we do in copy constructor and assignment operator. This is necessary as inside 'move' constructors we need to change the passing argument objects state as well. This can not be achieved if we pass the argument by 'const reference'. We also need to use double ampersand to distinguish from their copy constructors and assignment operators. This double ampersand also known as "rvalue" which actually 'move'  constructor would use.


Hope above explanation makes sense to reader. If some one has still some confusion, we would try to understand this by debugging this program and would verify when really 'move' constructors gets called.




//Code Begins

#include<iostream>
#include<cstring>
#include<algorithm>

template<typename T>
void display(const T& val) {
    std::cout<<val<<std::endl;
}

class x {
public:
    x(const char* n):length(20), ptr(nullptr){
        ptr = new char[length];
        std::fill(ptr, ptr+length,'\0');
        strncpy(ptr,n,length);
    }

    ~x() {
        delete [] ptr;
    }

    x(const x& rhs) {
        length = rhs.length;
        ptr = new char[length];
        std::fill(ptr,ptr+length,'\0');
        strncpy(ptr,rhs.ptr,length);
    }

    x& operator=(const x& rhs) {
        if(this != &rhs) {
            delete [] ptr;
            length = rhs.length;
            ptr = new char[length];
            std::fill(ptr,ptr+length,'\0');
            strncpy(ptr,rhs.ptr,length);
        }
        return *this;
    }

    x(x&& rhs) {
        length = rhs.length;
        ptr = rhs.ptr;
        rhs.length = 0;
        rhs.ptr = nullptr;
    }

    x& operator=(x&& rhs) {
        delete [] ptr;
        length = rhs.length;
        ptr = rhs.ptr;
        rhs.length = 0;
        rhs.ptr = nullptr;
        return *this;
    }

    void display_element(void) {
        if(ptr != nullptr) {
            display(ptr);
        }
    }

private:
    std::size_t length;
    char* ptr;
};



x function(void) {
    const char* na="Kumar";
    x o_c(na);
    return o_c;
}

void learn_move_constructor(void) {
    const char* nb="Mantosh";
    x o_a(nb);
    x o_b(o_a);

    o_b = o_a;

    const char* nc="Sharma";
    x o_d(nc);
    o_d = function();

    x o_e = std::move(o_d);

    o_a.display_element();
    o_b.display_element();
    o_d.display_element();
    o_e.display_element();

}

int main(int argc, const char* argv[]) {
    learn_move_constructor();
    return 0;
}
//Code Ends




When I run the above program, I get three messages on output console. From these novice readers will not be able to make much about internal   concept around this. Hence below I have explained this concept using the gdb debugger with appropriate explanation whereever applicable. Here we can put the break points on 'move constructor' and 'move assignment operator' and 'destructor' as  these are important functions at this point. Remaining 3 functions  are well known to us as its not something which is introduced in C++11.



//Debugger Output Begins

//Put the break point on the move constructor
(gdb) b x::x(x&&)
Breakpoint 2 at 0x400e92: file test_2.cpp, line 41.

//Put the break point on the move assignment operator
(gdb) break x::operator=(x&&)
Breakpoint 3 at 0x400eda: file test_2.cpp, line 48.

//Put the break point on the destructor as we want to see how
//destructor behaves for the objects which has been moved.
(gdb) break x::~x()
Breakpoint 4 at 0x400d14: file test_2.cpp, line 19.

//Once break point set, continue/run the program.
(gdb) continue
Continuing.

Breakpoint 3, x::operator=(x&&) (this=0x7fffffffe0b0, rhs=...)
48     delete [] ptr;

//At this point(LineNumber:84), the object(o_c) from the
//function() would be assigned to o_d object in the function
//learn_move_constructor(). At this point both the objects
//contains some resources, so we need to delete this object
//resources before assigning from other. This is same as we
//do in the assignment operator.
(gdb) backtrace
#0  x::operator=(x&&) (this=0x7fffffffe0b0, rhs=...)
#1  0x0000000000400b22 in learn_move_constructor ()
#2  0x0000000000400c18 in main (argc=1, argv=0x7fffffffe1f8)

//At present, the following are the contents of both the
//objects.Once we are done the resources of 'rhs' should
//assigned to 'this' object and 'rhs' should be in empty state
//as when we would return from the function f() scope, the
//destructor for 'rhs' object would gets called.
(gdb) p *this
$1 = {
  length = 20,
  ptr = 0x603050 "Sharma"
}
(gdb) p rhs
$2 = (x &) @0x7fffffffe0c0: {
  length = 20,
  ptr = 0x603070 "Kumar"
}

//Do 'next' command till you reach to end of the
//x::operator=(x&&).
(gdb) next
49     length = rhs.length;
(gdb) next
50     ptr = rhs.ptr;
(gdb)
51     rhs.length = 0;
(gdb)
52     rhs.ptr = nullptr;
(gdb)
53     return *this;

//At this point we can see that now 'rhs' resources are moved to
//'this' object. 'rhs(0x7fffffffe0c0)' is in the empty state.
(gdb) p *this
$3 = {
  length = 20,
  ptr = 0x603070 "Kumar"
}
(gdb) p rhs
$4 = (x &) @0x7fffffffe0c0: {
  length = 0,
  ptr = 0x0
}

//We again continue from here and the next time program breaks when
//the destructor gets called for the 'rhs(0x7fffffffe0c0)' object.
//This can be verified from the address and their values. Now
//when destructor would called for this 'empty' object, it
//would not do anything. I mean 'delete[]' would simply ignore
//for 'nullptr'. This is what we wanted to achieve in 'move'.
(gdb) continue
Continuing.

Breakpoint 4, x::~x (this=0x7fffffffe0c0, __in_chrg= ...>)
19      delete [] ptr;

(gdb) backtrace
#0  x::~x (this=0x7fffffffe0c0, __in_chrg=<optimized out>)
#1  0x0000000000400b2e in learn_move_constructor ()
#2  0x0000000000400c18 in main (argc=1, argv=0x7fffffffe1f8)
(gdb) p *this
$6 = {
  length = 0,
  ptr = 0x0
}
(gdb) p this
$7 = (x * const) 0x7fffffffe0c0

//After this, again we do 'next' under gdb to execute next line.
//In the program, I have called std::move() to explain how we
//can make use of 'move' semantic explicitly when compiler
//may not recognize that stuff. The same way again it would
//move the resources from 'rhs' object and make its state 'empty'
//In this context, 'this' does not have any resources with him so it
//does not need to release any prior resources. This is the same as
//copy constructor.
(gdb) next
20     }
(gdb)
learn_move_constructor () at test_2.cpp:86
86     x o_e = std::move(o_d);
(gdb) p o_d
$8 = {
  length = 20,
  ptr = 0x603070 "Kumar"
}

//At this point, move constructor gets called and which
//would do the same thing, assign the resources and make its
//own state 'empty'.
(gdb) continue
Continuing.

Breakpoint 2, x::x(x&&) (this=0x7fffffffe0d0, rhs=...)
41     length = rhs.length;

(gdb) backtrace
#0  x::x(x&&) (this=0x7fffffffe0d0, rhs=...)
#1  0x0000000000400b4c in learn_move_constructor ()
#2  0x0000000000400c18 in main (argc=1, argv=0x7fffffffe1f8)

(gdb) print this
$9 = (x * const) 0x7fffffffe0d0

(gdb) print rhs
$11 = (x &) @0x7fffffffe0b0: {
  length = 20,
  ptr = 0x603070 "Kumar"
}

//These are the move constructor linw, which is executing here.
(gdb) next
42     ptr = rhs.ptr;
(gdb)
43     rhs.length = 0;
(gdb)
44     rhs.ptr = nullptr;
(gdb)
45    }

//At this point we can see that 'rhs' resource has been moved to
//'this'. At this point also there would not be any problem with
//destructor call as 'rhs' state are still in destructible state.
(gdb) print rhs
$12 = (x &) @0x7fffffffe0b0: {
  length = 0,
  ptr = 0x0
}
(gdb) print *this
$13 = {
  length = 20,
  ptr = 0x603070 "Kumar"
}

//Debugger Output Ends


Friday, January 10, 2014

Chapter:05 Static Assert


Fundamental
=========



Static assert concept is like compile time equivalent to "assert()".  In past we all have been using assert() in different places in our code bases. "assert()" is simple yet very powerful tool which gives many useful information when you are running the debug version of your executable."assert()" gets such functionality by calling "abort()" which ultimately terminate the program at that time. By this way we normally get all useful information close to the root cause of the problem. By this way we can fix all such problem and then in the release version of our executable, we can remove "assert()" or we can define the NDEBUG macro by which "assert()" call gets ignored under the release version.



Now just imagine, wouldn't it be beautiful if  similar functionality is achieved at compile time rather than run time. Static assert concept has been introduced to achieve this functionality. Obviously there would be some limitation if some functionality works in compile time, as many important things are not known at compile time else the world would have been so nice and beautiful.


Static assert only evaluates the expression which happens to be the constant expression(constexpr/const) type. This limitation does not hold true for "assert()" functionality. However while learning this concept, I found that actually this limitation is not bad, but it sort of forces  good programming practices to be applied. I find that many times we define our variables  as literals or static/global variable or local variable type which never gets changed in program execution. Mostly we can do the same thing using 'constexpr/const' if we do slight change in our way of thinking. I know these lines might look like a bit philosophical, however, at this point, I can only share what I felt over the period of learning these concepts. Hopefully readers would realize the same in near future.



Uses
====


Now lets write some basic program using static assert concept. The below program actually examines the size of integer data with a constexpr variable. We all know that size of integer or any data type may vary depending on various machine  architectures and whether machine is 32 or 64 bit type. And suppose that you have written your program logic depending on the size of integer value, you may want to validate that logic during the compilation time of your program rather than gets impacted in the form of some nasty run time error. In such circumstances, static assert would be very helpful and the below program actually does the same thing.



//Code Begins
#include<iostream>

void learn_static_assert(void)
{   
 /* change it to 4,so that program can compile */
 constexpr int intsize = 8;
 static_assert(intsize <=sizeof(int),"integers are too small");
 int x{0};
 x = intsize*intsize;
 std::cout<<x<<std::endl;
}

int main(int argc, const char* argv[])
{
 learn_static_assert();
 return 0;
}

//Code Ends



When I compile the above program, I get the following output which is expected on my machine where size of integer is 4 byte. However inside static assert function, there is a check whether size of integer is less than 8 byte. This will not hold true under out circumstances. So the program will print the static assert message and abort the compilation of the program.





//Console Output Begins

$ g++ -g -gdwarf-2 -std=c++11 -Wall test_1.cpp -o test_1
test_1.cpp: In function ‘void learn_static_assert()’:
test_1.cpp:7:2: error: static assertion failed: integers are too small
  static_assert(intsize <=sizeof(int), "integers are too small");
  ^

//Console Output Ends



To illustrate that static assert does not play any role in the run time,  lets change the above program so that it can compile successfully. If we change the 'intsize' to 4 or less, which was causing the static assert to fail, this program would compile. Now we run/debug this program under "gdb",we can see by ourself that whether static assert line actually gets executed or not. When I did 'step' command to the static assert line "gdb" goes to next line instead of doing anything on static assert line. I also looked the "disassemble" command result and did not find any such instruction in the assembly code which shows any static assert piece of  instruction is there. This confirms that, this does not have any role in the run  time of program.



//Debugger Output Begins

(gdb) break main
(gdb) run
Breakpoint 1, main (argc=1, argv=0x7fffffffe1f8) at test_1.cpp:16
16        learn_static_assert();
(gdb) step
learn_static_assert () at test_1.cpp:6
6        constexpr int intsize = 4;
(gdb) disassemble learn_static_assert
Dump of assembler code for function learn_static_assert():
   0x0000000000400820 <+0>:      push   %rbp
   0x0000000000400821 <+1>:      mov    %rsp,%rbp
   0x0000000000400824 <+4>:      sub    $0x10,%rsp
=> 0x0000000000400828 <+8>:   movl   $0x4,-0x8(%rbp)
   0x000000000040082f <+15>:    movl   $0x0,-0x4(%rbp)
   0x0000000000400836 <+22>:    movl   $0x10,-0x4(%rbp)
   0x000000000040083d <+29>:    mov    -0x4(%rbp),%eax
   0x0000000000400840 <+32>:    mov    %eax,%esi
   0x0000000000400842 <+34>:    mov    $0x601060,%edi
   0x0000000000400847 <+39>:    callq  0x4006a0 <_ZNSolsEi@plt>
   0x000000000040084c <+44>:    mov    $0x400700,%esi
   0x0000000000400851 <+49>:    mov    %rax,%rdi
   0x0000000000400854 <+52>:    callq  0x4006f0 <_ZNSolsEPFRSoS_E@plt>
   0x0000000000400859 <+57>:    leaveq
   0x000000000040085a <+58>:    retq  
End of assembler dump.
(gdb) step
8        int x{0};
(gdb) n
9        x = intsize*intsize;
(gdb) c
Continuing.
16

//Debugger Output Ends




The real use of static assert is in the generic programming concept. We  all know that how difficult it is to understand the compilation error message when we use the STL or any other template based program. To improve this functionality for template based program, "concept" is planned to introduced in C++14.This hopefully would be great for us and after this we need not worry for these nasty compilation error messages. I think real bad compilation error is one of the main reason why everyone in C++ community prefer not to use template based programs as they should have been by now. This is serious problem over the years, and hence Bjarne Stroustrup and ISO C++ standard committee had proposed the "concept" solution for these problems.


However at present we are in C++11 world and it would take some time when "concept" would be introduced and understood by us. For now we can think  as "concept" are like predicates which would work in compile time. I think "concept" would or must  use static assert and type traits functionality in its implementation, which is available at present in the language. The examples discussed in this chapter are rather simple. Think how you can apply these language feature to implement type checking feature for template based programs in real sophisticated scenario. These are not so easy to learn and apply. At least I found it bit difficult and it took some time for me to understood it even partially.



The below program checks whether argument type is  float for the function "f()". If  by some means somewhere some code actually tries to pass the non-float type data to the "f()", static assert would abort the compilation. This is great because if due to some mistake, if your program would be doing the implicit type conversion while passing argument to "f()", it would get caught at compile time.
It's great and that too it does it in the compile time.



//Code Begins
#include<type_traits>
#include<iostream>

template<typename T>
constexpr bool Is_floating_point() {
 return std::is_floating_point<T>::value;
}

template<typename T>
void  f(T& a)  {
 static_assert(Is_floating_point<T>(), "Non-Float Type Data");
}

void learn_static_assert_and_typetraits(void) {
 float y{10.0};
 f(y);
 float x{100};
 f(x);

 float sum{0.0};
 sum=x+y;
 std::cout<<sum<<std::endl;
}

int main(int argc, const char* argv[]) {
 learn_static_assert_and_typetraits();
 return 0;
}

//Code Ends




When I compile the above program, I get the following compilation error when someone tries to pass the argument which happens to be "int" type.


//Console Output Begins

$ g++ -g -gdwarf-2 -std=c++11 -Wall test_2.cpp -o test_2
test_2.cpp: In instantiation of ‘void f(T&) [with T = int]’:
test_2.cpp:20:6:   required from here
test_2.cpp:12:3: error: static assertion failed: Non-Float Type  Data
   static_assert(Is_floating_point<T>(), "Non-Float Type  Data");
   ^
}
//Console Output Ends



"malloc()" is very important function in C/C++ program. However we all know that this function can create all sorts of problem if you are not aware of some of its internal concepts. The argument type of "malloc()" is of 'size t' type which is typedef of some unsigned. Now if our program passes the argument to "malloc()" by 'signed int' variable and if it becomes some negative value due to some reason, we are in big big trouble. Because under this situation, system would interpret your 'signed in' variable to 'unsigned' which would be very very large value. Due to this, "malloc()"would return NULL to its caller.



At many obvious places in our program we normally do not check the return address by "malloc()" even though it should be done as good programming practice. This would lead to program crash at the point depending on how you have handled/used this returned memory in code. This is nasty and not so easy bug to identify in real complex system.


Just to make "malloc()" more type safe, I have written the below program. I would not say that this is the ideal/complete solution for the problem which I have discussed above. Nevertheless it shows the reader how we can use these simple static asserts and type traits language mechanism in efficient way in our program.



//Code Begins

#include<type_traits>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<iostream>

template<typename T>
void display(const T& val) {
 std::cout<<val<<std::endl;
}

template<typename T>
constexpr bool Is_unsigned_number() {
 return std::is_unsigned<T>::value;
}

template<typename T>
void  check_unsigned(T& a)  {
 static_assert(Is_unsigned_number<T>(), "Non Unsigned Type  Data Found");
}

template<typename T>
void* my_malloc(T val) {
 /* Comment Out The Below check and see how program crash */
 check_unsigned(val);
 return malloc(val);
}


void learn_static_assert_and_typetraits(void) {
 constexpr std::size_t sz1{10};
 void* p_a=my_malloc(sz1);
 *(int *)p_a=sz1;

 constexpr int sz2{-1};
 void* p_b=my_malloc(sz2);
 *(int *)p_b=sz2;
}

int main(int argc, const char* argv[]) {
 learn_static_assert_and_typetraits();
 return 0;
}

//Code Ends




When I compile the above program, I get the following compilation error where program tries to pass the 'signed int' variable.


//Console Output Begins

$ g++ -g -gdwarf-2 -std=c++11 -Wall test_4.cpp -o test_4
test_4.cpp: In instantiation of ‘void check_unsigned(T&) [with T = int]’:
test_4.cpp:26:21:   required from ‘void* my_malloc(T) [with T = int]’
test_4.cpp:38:26:   required from here
test_4.cpp:20:3: error: static assertion failed: Non Unsigned Type  Data Found
static_assert(Is_unsigned_number<T>(), "Non Unsigned Type  Data Found");
^

//Console Output Ends




If we comment out the function which actually does the argument type checking before the actual “malloc()” call we can verify that program would crash at run time. This is because we have not done NULL check. But from my experience I can tell you that this is not so non obvious situation in real code. You can verify by yourself,by commenting that piece of code as mentioned in the code comment as well. I guess by now reader would slowly be realizing the power and beauty of these simple concepts.



//Debugger Output Begins

(gdb) break main
(gdb) run

Breakpoint 1, main (argc=1, argv=0x7fffffffe1f8)
44            learn_static_assert_and_typetraits();
(gdb) c
Continuing.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400751 in learn_static_assert_and_typetraits ()
39    *(int *)p_b = sz2;
(gdb) bt
#0  0x0000000000400751 in learn_static_assert_and_typetraits ()
#1  0x000000000040076d in main (argc=1, argv=0x7fffffffe1f8)
(gdb) p p_b
$1 = (void *) 0x0
(gdb) info locals
sz1 = 10
p_a = 0x602010
sz2 = -1
p_b = 0x0

//Debugger Output Ends



The below program explains how we can check whether a particular class is polymorphic type or not. There are many such type traits functions introduced in C++11. Please read those functions and think how you can use those in your program depending on your requirement. 


In the current example, I have written one class which has more than 'virtual' methods. Clearly, this is of polymorphic type.  The other class in the program is 'std::vector'. This is not of polymorphic type and it should not be implemented as polymorphic by any vendor. These simple check can be further used whether we create the object on free store or not. Because it does not make much sense to create the object on free store of the class which is of 'concrete' type and not 'polymorphic' type. Hope it make some sense to reader what I am trying to convey.


//Code Begins

#include<type_traits>
#include<iostream>
#include<string>
#include<vector>

template<typename T>
void display(const T& val) {
 std::cout<<val<<std::endl;
}

class base
{
public:
 base(std::string n): name(n) {}
 base(): base{"base"} {}
 virtual std::string get_name(void) { display(name); }
 virtual ~base() { }   
private:
 std::string name;
};

template<typename T>
constexpr bool Is_valid_poly() {
 return std::is_polymorphic<T>::value;
}

template<typename T>
void  check_polymorphic(T& a)  {
 static_assert(Is_valid_poly<T>(), "Its Not Polymorphic Class");
}


void learn_static_assert_and_typetraits(void) {
 base obj;
 check_polymorphic(obj);   
               
 std::vector<int> obj2;
 check_polymorphic(obj2);
}

int main(int argc, const char* argv[]) {
 learn_static_assert_and_typetraits();
 return 0;
}

//Code Ends




When I compile the above program,I get the following compilation error.


//Console Output Begins

$ g++ -g -gdwarf-2 -std=c++11 -Wall test_5.cpp -o test_5
test_5.cpp: In member function ‘virtual std::string base::get_name()’:
test_5.cpp:17:55: warning: no return statement in function
returning non-void [-Wreturn-type]
   virtual std::string get_name(void) { display(name); }
                                                       ^
test_5.cpp: In instantiation of ‘void check_polymorphic(T&)
[with T = std::vector<int>]’:
test_5.cpp:39:25:   required from here
test_5.cpp:30:3: error: static assertion failed:
Its Not Polymorphic Class
static_assert(Is_valid_poly<T>(), "Its Not Polymorphic Class");
 ^

//Console Output Ends

Chapter:04 Range For Statement

Fundamental
=========


"FOR" loop is one of the most common logic in programming and it's normally used when we want to traverse the each member in sequence. But one fundamental problem with basic for loop is, we need to mention the size for the loop to terminate. This is a problem and a source of error because if there is any mistake while passing the size information, we would be in big trouble. These errors are one of the most common cause of Memory Overflow/Underflow situation.

In C++11, a new range-based for loop has been introduced. Here you don't need to pass any size information of your input sequence. The piece of code which uses this, looks very compact and beautiful. This range-based for loop works for all standard containers and even for default array. Basically any sequence which provides the begin() and end() interface, it should work. So if we plan to write any new container type class, we should provide these interfaces to work well with range-based for loop. begin() and end() interfaces are also required if we want to use the STL defined algorithms anyway.


Range-based for loop with "auto" feature works very smoothly. The old rule applies here as well regarding how we should store a particular member in sequence. If you just want to fetch the members where you do not want to modify "const reference" should be used. In other cases where we want to read and update we should use either by "value" of by "reference".


Uses
===

The below program demonstrates that, how the same piece of code works fine
for almost all sequential type containers which basically provides the begin()
and end() interface.



//Code Begins
#include<iostream>
#include<vector>
#include<string>
#include<list>
#include<array>

template<typename C>
void display_container_elements(C& cnt)
{
 for(const auto& index: cnt)
    std::cout<<index<<"\t";
 std::cout<<"\n";
}

void learn_range_for_loop(void)
{   
 constexpr std::size_t size{5};
 int carray[size]={1,2,3,4,5};
 display_container_elements(carray);

 std::array<int,size> var_a{6,7,8,9,10};
 display_container_elements(var_a);

 std::vector<int> var_b{11,12,13,14,15};
 display_container_elements(var_b);

 std::list<int> var_c{16,17,18,19,20};
 display_container_elements(var_c);

 std::string var_d{"MantoshKumar"};
 display_container_elements(var_d);
}

int main(int argc, const char* argv[])
{
 learn_range_for_loop();
 return 0;
}

//Code Ends





When I run the above program, I get the following output.



//Console Output Begins

$ ./test
1        2    3       4      5   
6        7    8       9    10   
11    12    13    14    15   
16    17    18    19    20   
M    a    n    t    o    s    h    K    u    m    a    r

//Console Output Ends


Now,I can explain how we should use range-for loop in the scenario where we want to modify the elements of sequence. Under this scenario we should not use the 'const reference'. Below code basically stores the "std::string" in "std::array". Now if we want to modify each string value and store back to "std::array" we can do as following example. Later on, I have also printed the elements of  sequence before and after the change. While displaying(just reading), it makes sense that we should use 'const reference'.



//Code Begins

#include<iostream>
#include<string>
#include<array>

void learn_range_for_loop(void)
{   
 constexpr std::size_t  size{3};
 typedef std::array<std::string,size> myarray;
 myarray arr_x{"aa", "bb", "cc"};

 std::string tmp = "xx";
       
 for(const auto& i: arr_x)
   std::cout<<i<<"\t";
 std::cout<<"\n";
                     
 for(myarray::value_type& x: arr_x)
   x = x + tmp;

 for(const auto& i: arr_x)
   std::cout<<i<<"\t";
 std::cout<<"\n";

}



int main(int argc, const char* argv[])
{
 learn_range_for_loop();
 return 0;
}

//Code Ends






When I run the above program, I get the following output which is expected.



//Console Output Begins
\begin{verbatim}
$ ./test
aa    bb    cc   
aaxx    bbxx    ccxx   

//Console Output Ends









Thursday, January 9, 2014

Chapter:03 Std::Array

Fundamental
========

"std::array" is a class template for storing fixed-size sequence of objects.  This
has been introduced in the C++11 standard to replace "array" data structure. The major problem with the default "array" is it does not have the idea of its size. This causes a major problem as users need to store the size of the "array" which needs to be passed wherever along with the array base pointer. I mean size information is not well encapsulated within "array" data structure logic. However "array" structure is very popular because of its simplicity and  efficiency. So "std::array" has been designed so that user is able to use it instead of an "array", and moreover without loosing efficiency. On the other side "std::array" provides the interface similar to well behaved containers like "std::vector". Due to these flexibility, I believe that "std::array" would become very popular container class and it would replace the default "array". Following are key concepts about "std::array" container class:


1. Efficiency Comparable to default "array".
2. Interfaces available to perform low level operation as default "array".
3. Interfaces/Operation similar to the standard container class "std::vector".
4. Size information gets encapsulated within the object of class "std::array".



Uses
===

Let us now write a small program which demonstrates how we can use "std:array" in the place of default "array". The below program is self-explanatory and describes the basic usages of "std::array". The key point to be noted here is, user code need not to pass the size information in the argument. In addition to that, it behaves as a well defined container classes(for example std::vector) which allowed us to sort the elements easily.


This indeed encapsulates many things in one simple class.I must say it is
one of my favourite container class because of elegance and simplicity.


//Code Begins
#include<array>
#include<iostream>
#include<algorithm>

constexpr std::size_t size=5;
typedef std::array<int,size> myarray;

void double_entry(myarray& val)
{
    for(myarray::size_type i=0; i<val.size(); ++i)
        val[i] = 2*val[i];
}

void display(myarray& val)
{
    for(myarray::size_type i=0; i<val.size(); ++i)
        std::cout<<val.at(i)<<"\t\t";
    std::cout<<"\n";
}

void learn_std_array(void)
{
    myarray arr_x{9,10,5,4,3};
    display(arr_x);
    double_entry(arr_x);
    display(arr_x);
    std::sort(arr_x.begin(),arr_x.end());
    display(arr_x);
}

int main(int argc, const char* argv[])
{
    learn_std_array();
    return 0;
}

//Code Ends



The Output of the above program is as follows.


//Console Output Begins

$ ./test
9        10       5         4          3       
18      20      10        8          6       
6        8        10        18        20   

//Console Output Ends



If you are a diehard fan of old style "array”, do not feel disheartened. If you still like to use the array elements using pointer mechanism,"std::array" provides interface for you. That’s the beauty of this class. Additionaly I would also explain using debugger, how memory management of "std::array" works. I have already mentioned that this class uses stack memory instead of free store to make things simple and optimal. However with stack (local) memory, we should also be careful while returning something to caller scope.


The old rule is applicable here as well. If you need to return "std::array" from the function, return it by value and not by reference. However this would be bit costly as there is no concept like "move constructor" for the "std::array". Due to this it would copy all elements and its linear time operation. By the way this copy of all elements is applicable for default "array".


//Code Begins
#include<array>
#include<iostream>

constexpr std::size_t size=5;
typedef std::array<int,size> myarray;

/* Change the return type from myarray&    */
/* to myarray and check the output.The     */
/* below function is wrong and it contains */
/* the serious error. */
myarray& double_entry(myarray& val)
{
  auto *base=val.data();
 myarray arr_ret;
 auto *ret_base=arr_ret.data();
 for(myarray::size_type i=0; i<val.size(); ++i)
  *(ret_base+i)=2*(*(base+i));
  return arr_ret;
}

void display(myarray& val)
{
  for(myarray::size_type i=0; i<val.size(); ++i)
      std::cout<<val.at(i)<<"\t\t";
  std::cout<<"\n";
}

void learn_std_array(void)
{
 myarray arr_x{9,10,5,4,3};
 display(arr_x);
 myarray arr_y=double_entry(arr_x);
 display(arr_y);
}

int main(int argc, const char* argv[])
{
 learn_std_array();
 return 0;
}

//Code Ends



The Output of the above program is as follows.


//Console Output Begins
$ ./test(With myarray interface. This correct way to use )
9          10        5          4        3       
18        20        10        8        6

$ ./test(With myarray& interface. This is serious bug)
test.cpp: In function ‘myarray& double_entry(myarray&)’:
test.cpp:14:10: warning: reference to local variable
‘arr_ret’ returned [-Wreturn-local-addr]
  myarray arr_ret;
          ^
9        10        5        4        3       
-1999   32719   419673  0       0

//Console Output Ends



To understand the above behavior we need to know about how “std::array” actually manages its memory management. Again I believe gdb debugger log would help us understand better. I want to explain this with the correct code as I want to keep things simple while explaining these.




//Debugger Output Begins
(gdb) 12     for(myarray::size_type i=0; i<val.size(); ++i)

// This command would display all the local variables defined
// inside this function.
(gdb) info locals
i = 140737488347328
base = 0x7fffffffe0c0
arr_ret = {
  _M_elems = {2, 0, 4197341, 0, -139589008}
}
ret_base = 0x7fffffffe0e0


// This command would display all arguments passed to this function.
(gdb) info args
val = @0x7fffffffe0c0: {
  _M_elems = {9, 10, 5, 4, 3}
}


// The following command has been used to find out PID of the current
// program. This would be used to find out the stack segment region
// in the current process address space.
(gdb) info proc
process 6968
cmdline = './test'
cwd = './03_std array'
exe = './test'
(gdb) shell cat /proc/6968/maps|grep "stack"
7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0    [stack]


// I have displayed these range address into decimal as hex is not
// so natural to humans. I have also printed the base addresses of
// the two arrays. These address should lie in the stack segment
// range which can be confirmed from the below output.
(gdb) p/d 0x7ffffffde000
$1 = 140737488216064
(gdb) p/d 0x7ffffffff000
$2 = 140737488351232
(gdb) p/d 0x7fffffffe0e0
$3 = 140737488347360
(gdb) p/d 0x7fffffffe0c0
$4 = 140737488347328

// The below command would display the current stack trace.
(gdb) backtrace
#0  double_entry (val=...) at test.cpp:12
#1  0x0000000000400a54 in learn_std_array () at test.cpp:28
#2  0x0000000000400a80 in main (argc=1, argv=0x7fffffffe208)

// By finish command, we come out from the current frame to its
// caller. We can see that it return the complete array which
// would copied into variable arr_y. This is expensive.
(gdb) finish
Run till exit from #0  double_entry (val=...) at test.cpp:12
learn_std_array () at test.cpp:29
29     display(arr_y);
Value returned is $5 = {_M_elems = {18, 20, 10, 8, 6}}
(gdb) next
18        20        10        8        6       
30    }


//Debugger Output Ends





Wednesday, January 8, 2014

Chapter:02 Initializer List

Fundamental
========

List initialization is initialization of an object or reference from braced-init-list. Such an initializer is called initializer list, and the comma-separated initializer-clauses of the list are called the elements of the initializer list. This concept can be used to initialize any object and due to this it is also known as the universal initializer. In fact now it has been included to all standard container of C++. I think the key about this is, it encapsulate the initialization concept in a class. Now I would write a small program which would require to explain this concept. I would also use the debugger result to explain some of the concepts and why they behave in that way.


//Code Begins
#include<initializer_list>

void learn_initializer_list(void)
{
    std::initializer_list<int> ilist_x;
    std::initializer_list<int> ilist_y {1,2,3,4,5};
    auto sz_x = ilist_x.size();
    auto sz_y = ilist_y.size();

    auto itrs = ilist_y.begin();
    std::initializer_list<int>::const_iterator itre = ilist_y.end() - 1;
}

int main(int argc, const char* argv[])
{
    learn_initializer_list();
    return 0;
}

//Code Ends



The above simple program basically creates the two object of initializer list. I have used "auto", the another new feature introduced in C++11 in the current program. This class provides the begin() and end() method to access the members. However if we see the standard specification, this class do not provide any non const pointer/iterator mechanism. This is because initializer list class do not allow any modification once members of this class has been assigned with some values. This make complete sense and we would get to know once I would try to explain this with the debugger result.


//Debugger Output Begins
// This command would simply displays all the local variable defined
// inside this function.
(gdb) info locals
ilist_y = {
_M_array = 0x400670,
_M_len = 5
}
sz_x = 0
itrs = 0x400670
itre = 0x400399
ilist_x = {
_M_array = 0x0,
_M_len = 0
}
sz_y = 5
// These iterator are defined as const pointer. This is to optimize
// the read operation. It also ensures the safety and if program
// tries to write into these memory, there would be compilation
// error.
(gdb) ptype itrs
type = const int *

// The size of the objects of this class is two word size.
(gdb) p sizeof(ilist_x)
$2 = 16
(gdb) p sizeof(ilist_y)
$3 = 16

// This is the key concept in this scenario. We know that variable
// "itrs" stores the base pointer of this list. Now just read the
// 5 word from this base address as there is 5 members intitialized
// in "ilist_y". We get the expected output.
(gdb) x/5dw 0x400670
0x400670 <._0>: 1 2 3 4
0x400680 <._0+16>: 5


// Here i am trying to identify in which memory segment the base
// address "0x400670" lies. As we know that on GNU/Linux machine, we
// can check the virtual address map layout of any program. I have
// also used the grep command to shrink the output which is
// required to explain this.
(gdb) info proc
process 4732
cmdline = './test'
cwd = './c++11_notes'
exe = './c++11_notes/test'

// Now we can see that "0x400670" lies in the first segment in the
// below list. If we look more carefully, we can see that this is
// read-execute only segment(r-xp). Its look like std::initializer_
// list stores the members on the some part of .data segment.
// Normally any global/static variable initialized with some values
// stored in this segment which is write protected. This explains why
// it is serious error if we try write into these memory by any means
// .This is the reason why standard have not provided any non const
// interface so that client program can modify these. I think its
// consistent with the fact this class encapsulate the initialization
// of object. If you want to modify these values, first you should
// store it into some container and then you can modify these values
// within that container class.
(gdb) shell cat /proc/4732/maps|grep "test"
00400000-00401000 r-xp 00000000 08:03 10237508 ./test
00600000-00601000 r--p 00000000 08:03 10237508 ./test
00601000-00602000 rw-p 00001000 08:03 10237508 ./test
//Debugger Output Ends







Advantage
=======

In above section, we discussed that why initializer list provides const iterator in its all interfaces. This is very important from safety perspective and it also optimizes the reading members from it. Now let me try to use the const cast mechanism to remove const from these pointer and try to write into this memory. By now, we know this could be suicidal and something nasty would be the result.It would also demonstrate that we should try to avoid these casting mechanism uses in our program.



//Code Begins
#include<initializer_list>
#include<iostream>

void learn_initializer_list(void)
{
    std::initializer_list<int> ilist_y {1,2,3,4,5};
    auto itrs = ilist_y.begin();
    std::cout<<"First Element:"<<*itrs<<"\n";
    int* dangerous = const_cast<int*>(itrs);
    *dangerous = 100;
}

int main(int argc, const char* argv[])
{
    learn_initializer_list();
    return 0;
}


//Code Ends



If we run the above program, it would crash with SIGSEGV. This was expected as we did something which was not advised to do. Internally it stores members information into the memory segment which is write protected. Initializer list will not allow such a thing, if user tries to do such things accidentally, there would be compile time error. This is one of the great advantage of this mechanism.



This mechanism also provides the type safety and avoids any conversions that may cause information loss. This is major benefit from this mechanism which the programmer gets for free.


//Code Begins
#include<initializer_list>
#include<vector>

void learn_initializer_list(void)
{
    int var_x{int{3}};
    int var_y {int{1.2}};
    int var_z = 5.5;
    std::vector<int> vec_y{1, 2, 3.4, 4};
}

int main(int argc, const char* argv[])
{
    learn_initializer_list();
    return 0;
}

//Code Ends




When I compile the above program on GNU/Linux machine gcc 4.8.1. I get the following message on my console.


//Compiler Output Begins
$ g++ -g -gdwarf-2 -std=c++11 -Wall test.cpp -o test
test.cpp: In function ‘void learn_initializer_list()’:
test.cpp:7:20: warning: narrowing conversion of ‘1.2e+0’ from
‘double’ to ‘int’ inside { } [-Wnarrowing]
int var_y {int{1.2}};
^ test.cpp:9:37: warning: narrowing conversion of ‘3.3999e+0’
from ‘double’ to ‘int’ inside { } [-Wnarrowing]
std::vector vec_y{1, 2, 3.4, 4};
//Compiler Output Ends



Uses
===
No language feature can be used in isolation to deal with the non trivial problem. Initializer list concept can/should be used when we are writing a new container class or container type of class.


I was reading about the "std::array" container class which is also introduced in C++11 standard. I would cover this topic in detail in the subsequent chapter. But for current discussion,"std::array" does not have a public constructor. However there is other methods provided in the standard to initialize the members after we created the object."std::array" actually uses stack memory not the heap memory to store all members. This is the reason why standard has not been provided any public constructor.


"std::array" has been designed to match the performance of default array in C/C++ language which uses the stack memory. However, just to match the interface with the other containers classes, I have improved the "std::array" so that it can have the public constructor and behave like other standard container. While doing so I had to use the initializer list mechanism for my new class. The following program shows how we can use this concept in implementing container type classes.



//Code Begins

#include<initializer_list>
#include<array>
#include<iostream>

template<typename T, std::size_t max>
class myarray: public std::array<T, max>
{
public:
    typedef std::array<T,max> arraytype;

    myarray() {
        arraytype::fill(T{});
    }

    myarray(std::size_t sz, T val) {
        arraytype::fill(T{val});
    }

    myarray(std::initializer_list<T> lst) {
        auto * p = lst.begin();
        if(lst.size() >= arraytype::size() )
        {
            for(std::size_t cnt = 0; cnt < arraytype::size(); ++cnt)
            {
                arraytype::operator[] (cnt) = p[cnt];
            }
        }
        else
        {
            std::size_t cnt{0};
            for(; cnt < lst.size(); ++cnt)
            {
                arraytype::operator[] (cnt) = p[cnt];
            }

            for(std::size_t remain = cnt; remain < arraytype::size(); ++remain)
            {
                arraytype::operator[] (remain) = T{};
            }              
        }
    }

};


void learn_initializer_list(void)
{
    constexpr std::size_t sz {5};
    myarray<int, sz> var_x;
    myarray<int,sz>  var_y(sz, 1);
    myarray<int,sz>  var_z{7,8,9};

    for(std::size_t i = 0; i < var_x.size(); ++i)
        std::cout<<var_x[i]<<"\t"<<var_y[i]<<"\t"<<var_z[i]<<"\n";
}

int main(int argc, const char* argv[])
{
    learn_initializer_list();
    return 0;
}