Sunday, 24 January 2016

C++ default member functions provided by compiler

If you declare an empty class like below, compiler will add all the below functions by default:
class T{}

====
class T {
        // default constructor
        T() {}

        // copy constructor
        T(T const& rhs) {}

        // destructor
        ~T() {}

        // assignment operator
        T& operator=(T const& rhs) { return *this; }

//Move constructor C++11
T(T&& other){}

//Move assignment operator C++11
T& operator=(T&& other){}
};
====

Thursday, 21 January 2016

Type Casting in C++


dynamic_cast: Only upcast allowed

  Base * pb1 = new Derived;
  Base * pb2 = new Base;
  Derived * pd;

  pd = dynamic_cast<Derived*>(pb1); //Success. pd will be Non-Null value
  pd = dynamic_cast<Derived*>(pb2); //Failure. pd will be NULL


static_cast: Upcast and downcast both allowed

  Base * pb = new Base;
  Derived * pd = static_cast<Derived*>(pb); //Success. Programmer should ensure the safety.


reinterpret_cast: converts any pointer type to any other pointer type, even of unrelated classes.

  class A { /* ... */ };
  class B { /* ... */ };
  A * a = new A;
  B * b = reinterpret_cast<B*>(a); 

const_cast: manipulates the constness of the object pointed by a pointer, either to be set or to be removed.

  void display (char * str)
  {
    cout << str << '\n';
  }

  int main () {
    const char * c = "sample text";
    display ( const_cast<char *> (c) );
    return 0;
  }

C++11 new features

auto: Used for type inference

  //For variables
  auto i = 42;        // i is an int
  auto l = 42LL;      // l is an long long
  auto p = new foo(); // p is a foo*
  
  //For iterators
  std::map<std::string, std::vector<int>> map;
  for(auto it = begin(map); it != end(map); ++it) {}

  //For function return types
  template <typename T1, typename T2>
  auto compose(T1 t1, T2 t2) -> decltype(t1 + t2)
  {
     return t1+t2;
  }
  auto v = compose(2, 3.14); // v's type is double


nullptr:

  void display(int a){ cout<<"Integer version called"<<endl; }
  void display(int *p){ cout<<"Int pointer version called"<<endl; }
  void display(long a){ cout<<"long version called"<<endl; }
  int main()
  {
        display(nullptr); //Calls pointer version
        display(NULL); //Calls long version
        display(0); //Calls int version
  } 

range-based for loop:

  string str = "United Online";
  for(char c : str)
      cout<<c;

override:

  - For runtime polymorphism,
1. Signatures of functions must be same in both Base and Derived classes.
2. Base class pointer is used to achieve this.
base * pb = new Derived();
  - But there is a chance that by mistake the function signature is different in both Base and Derived     classes. Unnoticeably, we might be thinking that runtime polymorphism will work and Derived   version will be called. But ideally just compile time polymorphism will happen and Base version will be called.
  - To avoid such bugs, 'override' is introduced. It will error out if function signatures are different.

  class parent {
        public:
          virtual void handle_event(int something) {cout<<"Boring default code"<<endl;}
  };

  class child : public parent {
        public:
                // force handle_event to override a existing function in parent
                // error out if the function with the correct signature does not exist
                virtual void handle_event(int something) override {cout<<"New exciting code"<<endl;}
  };

  int main() {
      parent *p = new child();
      p->handle_event(1);
  }


final:

  - To stop Derived class overriding Base class virtual function.
  - To stop inheriting Base class it self.

enums:

  //Old style (Global scope)
   enum Animals{Cat, Dog, Chicken};
   enum Birds{Eagle, Duck, Chicken}; //Error, Chicken is already used

   //New style (Seperate scope)
   enum class Fruits{Apple, Mango, Orange};
   enum class Colors : char{Red, Green, Orange};//Allowed, Fruits::Orange != Colors::Orange

smart pointers: used for reference counting and auto releasing of owned memory.
  • unique_ptr: should be used when ownership of a memory resource does not have to be shared (it doesn't have a copy constructor), but it can be transferred to another unique_ptr (move constructor exists).
  • shared_ptr: should be used when ownership of a memory resource should be shared (hence the name).
  • weak_ptr: holds a reference to an object managed by a shared_ptr, but does not contribute to the reference count; it is used to break dependency cycles (think of a tree where the parent holds an owning reference (shared_ptr) to its children, but the children also must hold a reference to the parent; if this second reference was also an owning one, a cycle would be created and no object would ever be released).
  On the other hand the auto_ptr is obsolete and should no longer be used.

lambdas: Nothing but anonymous functions

Eg: [](int n){cout<<n<<" ";}

BOOST BOOST_FOREACH example

#include <iostream>
#include <string>
#include <boost/foreach.hpp>

using namespace std;
using namespace boost;

int main()
{
        string str = "United Online";

        char c;
        BOOST_FOREACH(c, str)
        {
                cout<<c;
        }
        cout<<endl;

        list l = {1,2,3,4,5};
        BOOST_FOREACH(int i, l)
        {
                cout<<i;
        }
        cout<<endl;
}

BOOST scoped_ptr example

#include <iostream>
#include <boost/scoped_ptr.hpp>

using namespace std;
using namespace boost;

class C
{
        public:
                int a;
                int b;

                C(){cout<<"Constructor called"<<endl;}
                ~C(){cout<<"Destructor called"<<endl;}
};

int main()
{
        C * pC = new C;
        scoped_ptr<C> scp(pC);
        scp->a = 10;
        scp->b = 20;

        cout<<"a: "<<scp->a<<endl;
        cout<<"b: "<<scp->b<<endl;

        scp.reset();

        cout<<"a: "<<pC->a<<endl;
        cout<<"b: "<<pC->b<<endl;
}

BOOST shared_ptr example

#include <iostream>
#include <memory>

using namespace std;

class C
{
        public:
                int a;
                int b;

                C(){cout<<"Constructor called"<<endl;}
                ~C(){cout<<"Destructor called"<<endl;}
                int add(int a, int b)
                {

                }
};

int main()
{
        C * pC = new C;
        shared_ptr<C> scp(pC);
        scp->a = 10;
        scp->b = 20;

        shared_ptr<C> scp1(scp);
        cout<<"a: "<<scp->a<<endl;
        cout<<"b: "<<scp->b<<endl;

        scp.reset();

        cout<<"a: "<<pC->a<<endl;
        cout<<"b: "<<pC->b<<endl;

        scp1.reset();

        cout<<"a: "<<pC->a<<endl;
        cout<<"b: "<<pC->b<<endl;
}

STL vector example

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

using namespace std;

int main()
{
        //Initialize
        vector<int> v;
        for(int i = 0; i < 10; i++)
                v.push_back(i);

        int array[] = {100, 101, 102, 103};
        vector<int> v1;
        v1.assign(array, array + sizeof(array)/sizeof(array[0]));
        vector<int> v2(array, array + sizeof(array)/sizeof(array[0]));

        if(!v.empty())
                cout<<"Not empty"<<endl;

        //Insert
        v.resize(15);
        v[10] = 10;
        v[11] = 11;
        v.insert(v.begin()+12, 12);
        v1.insert(v1.begin()+4, 2, 30);
        v2.insert(v2.begin(), v1.begin(), v1.end());
        v.push_back(15);

        //Delete
        v.erase(v.begin());
        v.erase(v.begin(), v.begin()+2);

        //Search
        vector<int>::iterator it1 = find(v.begin(), v.end(), 7);
        cout<<"Found: "<<*it1<<" Index: "<<it1-v.begin()<<endl;

        if(v.empty())
                cout<<"Empty"<<endl;
        cout<<"Vector size: "<<v.size()<<endl;

        //Traverse
        cout<<"V: ";
        for(vector<int>::iterator it = v.begin(); it != v.end(); it++)
                cout<<*it<<" ";
        cout<<endl;
        cout<<"V1: ";
        for(vector<int>::iterator it = v1.begin(); it != v1.end(); it++)
                cout<<*it<<" ";
        cout<<endl;
        cout<<"V2: ";
        for(vector<int>::iterator it = v2.begin(); it != v2.end(); it++)
                cout<<*it<<" ";
        cout<<endl;


        //Clear
        v.clear();
}