Tuesday, November 12, 2019

c++11 features

C++11 Features:

1. Rvalue references and move constructors
 
Lvalue
R value
  Exam
lvalue is anything whose address is accessible. It means we can take address of lvalue using & operator
Rvalue is anything that is not lvalue. cannot take address of rvalue.

int x(lvalue) = 10(r value);
 int z (lvalue) = (x+1) (r value);
here we cannot take address of (x+1) but we can take z as it is l value int y = &z; 

 It also doesn’t persist beyond the single expression.
 int getVal()
{
     int val = 10;
     return val; value of return is temporary as after it returns it won't persist
}
int y = getval(); getval is rvalue which will not  get the address 

Rvalues of built-in data type is immutable
(x+1) = 10; //compiler  error cannot modify rvalue Getval() = 8; // compiler error cannot modify rvalue

Rvalue of user defined data type is not immutable
Class abc{
       int x;
       public:
           abc() :x(0) {}
            add(int val){ this.x +=val;}
}
abc getObj(){
      return abc();
}
Int main()
{
       abc * = & getObj(); //compiler error
       abc().add(10); // it increments value but add method here is r value.
}
Lvalue reference
R value reference

A Reference variable is an alias that always points to a an existing variable i.e
rvalue references can do what lvalue references fails to do i.e. a rvalue reference can refer to rvalues.
lvalue reference: int x =10;
int &z = x;// Works, but int &z = (x+2) //won’t work. As l value refers l values only.
 rvalue reference:
int &&z=(x+2); // is valid  as now z is rvalue reference with && is syntax
int &&y = getval(); // also works










































Move constructor: In addition to default, copy and copy assignment operator constructor c++11 introduced move constructor and move assignment operator constructor.
default, copy constructor, copy assignment operator constructors takes lvalue reference as a argument and just copy from source object to destination object means both the copies are present in source and destination objects. Where as in move constructor will take rvalue as a input and will move from source to destination object so source object empty after moving.
If user not implements the implicit defined move special member functions move their sub objects and data members in member wise.
Move constructor doesn’t allocate resources, shift the control of memory and passed object assigned to NULL.
Move assignment operator first check the passed object and this object then constructor doesn’t allocate resources, shift the control of memory, delete passed object data pointers  and passed object assigned to NULL.
abc::abc(abc&& obj);
abc& abc::operator=(abc&& obj)
abc::abc(abc &&obj)
{
      m_data = obj.m_data; //move
      obj.m_data = NULL; //reset passed object data to null
}
abc& abc::operator=(abc &&obj)
{
     If(&obj != this) //check before move
      m_data = obj.m_data; //move
      delete obj.m_data; //delete passed object
      obj.m_data = NULL; //reset its object data to null
      return *this; return new moved object
}




2. constexpr – Generalized constant expressions
    
Constexpr feature is for performance improvement of program by doing computations at compile time instead of run time.
 Ex1: constexpr rand(int x, int y) // here constexpr tells to compute the value at compile time.
       {
              return x+ y+20;
        }
       int val = rand(20, 30);
Ex2:

       int arrsize1(int x)                                 constexpr Int arrsize2(int x)
        {                                                              {
                 return x+1;                                           return x+1;
          }                                                             }
 int arr[arrsize1(20)]; //error as arrsize1() function will compute at run time
 int arr[arrsize2(20)]; //error as arrsize2() function will compute at compile time bcz of constexpr
Note: constexpr function must follow below conditions
       -  not a virtual function
       -  return type and its param should be in literal
       -  constexpr must refere global variable.
       -  constexpr function can call only other constexpr function not simple function
      - inside function not allow post, pre increment(++, --) expressions.
constexpr vs inline functions: inline means compiler to expand at at compile time, save time in function call overhead and evaluation done at run time, where as constexpr is evaluated at run time.
constexpr vs const:   constexpr is mainly for optimization while const is for practically const objects like value of Pi(3,14).  
valid, invalid places to use constexpr

3. Uniform initialization
    - It allows the consistency syntax to initialize the variables and class objects, initialization uses {} open close curly braces. initializer more
    - typename variable{arg1, arg2, arg3, ...}
    Ex:
            -. int x{}; //uninitialized built in type
            - .  int x{1}; //initialized built in type
            -. int arr[]{1,2,3,4}; //aggregate initializing
            - 
int* pi = new int[5]{ 1, 2, 3, 4, 5 }; //initializing dynamically allocated array

- class A { //initializing the class array member variable
int arr[3];
         public:
A(int x, int y, int z):arr{x,y,z};
               {
};
- std::vector<int> x{1,2,3} //Initializing the STL container
     
4. Type inference (auto)  auto
       auto keyword can be used in place of variable type to tell the compiler infer the variable type from the variable type is called type inference/type deduction.
       auto keyword is very useful to reducing the verbosity of the code.i.e
      for (std::vector <int>::iterator it = v.begin(); it!= v.end(); ++it) can be written
      for(auto it = v.begin(); it !=v.end(); ++it) // more readable as auto is simple to  write
   Notes:
      - auto key work cannot be used with function parameters ex: int fun(auto x, auto y) // not allowed
      - trailing return syntax Ex: auto func(int x, int y) -> int // it means return type is int
   
5. Range-based for loop  range based for loop
     easy iteration over the range of  elements, STL containers contain begin(), end() range of elements will be iterate easily with range based for loop.
   syntax: for(initialize starting value from range: range expression)
          ex: for(auto it : vec) // here vec is vector and it is iterator will assigned form begin() to end () element.
     for_each()UnaryFunction for_each( InputIt first, InputIt last, UnaryFunction f );
                 
     
        #include <iostream>
#include<vector>
#include<algorithm>

using namespace std;
class Sum{
   
  public:
       Sum():_sum(0){}
       int _sum;
       void operator()(int n){
           _sum += n;
       }
};
int main()
{
   cout << "Hello World" << endl;
   std::vector<int>vec{1,2,3,4,5,6,8};
   auto f = [](const int n){
       cout<<" "<<n;
   };
   auto f2 = [](int& n){
       n++;
   };
   for_each(vec.begin(), vec.end(),f);
   for_each(vec.begin(), vec.end(),f2);
   cout<<"\n";
   for_each(vec.begin(), vec.end(),f);
   Sum s = for_each(vec.begin(), vec.end(),Sum());
   cout<<"\n"<<s._sum;;
   return 0;
}


6. Lambda functions and expressions
    Anonymous / unnamed (no name to the function)/ lambda expressions are small snippet of code inside other functions.
    Syntax :      
 [ captureClause ] ( parameters ) -> returnType
   {
      statements;
   }
   capturescluse, parameters can be empty and return type is optional by
   default return type treated as auto.
   Ex: auto f = [] (){ cout<<"Hello Lamdas "<<endl}
 
The difference between the usage of functions and lambda functions boils down to two points:
  • We cannot overload lambdas.
  • A lambda function can capture local variables.
  • A lambda should be short and concise.
  • A lambda should be self-explanatory, especially since it does not have a name.


7. Explicit overrides and final
    Explicit: Explicit function specifier control the unwanted implicit type conversion.
    - It can only be used in declaration of class constructor within the class declaration.
    class abc{
               public:
                      abc(){}
                     abc(int val) : m_val(val){}
              private:
                     int m_val;
    };
    int main()
    {
          abc a=10;// compiler error
    }
   Override: Keyword override will make the compiler to check the base class to see if there is a virtual function with this exact signature. And if there is not, the compiler will show an error. 
    Final: final Sometimes you don’t want to allow derived class to override the base class’ virtual function. C++ 11 allows built-in facility to prevent overriding of virtual function using final specifier.
      
8. Null pointer constant (nullptr)
nullptr is a keyword that can be used at all places where NULL is expected. Like NULL, nullptr is implicitly convertible and comparable to any pointer type. Unlike NULL, it is not implicitly convertible or comparable to integral types

9. Strongly typed enumerations
     enum classes / scoped enumeration which makes the enums strongly scoped and typed.
 Ex:
enum class Color // "enum class" defines this as a scoped enumeration instead of a standard enumeration
    {
        RED, // RED is inside the scope of Color
        BLUE
    };
    enum class Fruit
    {
        BANANA, // BANANA is inside the scope of Fruit
        APPLE
    };
    Color color = Color::RED; // note: RED is not directly accessible any more, we have to use Color::RED
    Fruit fruit = Fruit::BANANA; // note: BANANA is not directly accessible any more, we have to use Fruit::BANANA
    if (color == fruit) // compile error here, as the compiler doesn't know how to compare different types Color and Fruit
        std::cout << "color and fruit are equal\n";
    else
        std::cout << "color and fruit are not equal\n";
   
10. Multithreading memory model
11. Thread-local storage
12.  Explicitly defaulted and deleted special member functions
13. Static assertions
14. General-purpose smart pointers
      
         Smart pointers are introduced to prevent the memory leaks
Unique_ptr<>:unique_ptr<> objects wraps around the raw pointer and its responsible for its life time. When these objects is destructed/out of scope then in its destructor it deletes associated raw pointer.
- A unique_ptr object is always the unique owner of associated raw pointer, we cannot copy only it’s a movable.
- It will be used when u want the single ownership of the resource 
- unique_ptr has its -> and * operator overloaded, so we can use similar like normal pointers.
   unique_ptr<int>uptr(new int);//unique pointer with raw pointer
    *uptr = 100;
    cout<<"pointer conent: "<<*uptr<<endl;
    int *rptr = new int();
    *rptr = 23;
    unique_ptr<int>uptr1(rptr);//from existing raw pointer
    cout<<"pointer conent: "<<*uptr1<<endl;
    unique_ptr<int>emptuptr;//empty unique pointer
    if(emptuptr == nullptr)
    {

        //reset will delete the associated raw pointer and unique_ptr make empty
        uptr1.reset();// resetting the unique pointer
        cout<<"unptr is empty if no raw pointer assined\n";
    }
   // unique_ptr<int>cuptr=uptr; //compilation error cannot assign
//    emptuptr = upter;// compilation error  cannot assign
    unique_ptr<int>muptr = std::move(uptr);
    if(uptr == nullptr)
    cout<<"Empty uptr after move\n";
    if(muptr != nullptr)
    cout<<"Not an empty after move got ownership: "<<*muptr<<endl;

//relese
    int *relptr = muptr.release(); //returns the associated raw pointer
    cout<<"raw pointer content: "<<*relptr<<endl;
shared_ptr<>:  is smart enough to automatically delete the associated pointer when its not used anywhere. Thus helps us to completely remove the problem of memory leaks and dangling Pointers.
- Shared_ptr will be used when shared ownership of resource needed
- It is a reference counting ownership model.
- Each shared pointer internally points to two memory locations i.e 1. pointer to the object 2. pointer to the control data that is used for reference counting.
Ex: shared_ptr<int>sptr(new int());
     1. pointer to the int object, 2. memory of reference counting now count value is 1.
- raw pointer object will be deleted once the reference count becomes zero(0).
- sptr.use_count() will give the reference count value now that is 1 as per above sptr object as not shared to other pointers.
- custom delete as a function pointer we should pass when you make shared pointer scenarios like array of object shown below example
 - custom delete can be lamda function, functor object as well example
 - shared pointer spport only -> , *.
 - shared pointer not support +, -, ++, --, [] operators.
int *ptr = new int();// raw pointer
  *ptr = 10;
  shared_ptr<int>sptr(ptr);//shared pointer from raw pointer
  cout<<"\nsptr count "<<sptr.use_count()<<" "<<*sptr<<endl;
  shared_ptr<int>p2(sptr);

  shared_ptr<int>p3 = p2;// compiler error not allowed assignment

  sptr.reset();//reset will decrease reference count by 1 and delete if count is 0.
  cout<<"\n refene count"<<sptr.use_count()<<" p2 "<<p2.use_count()<<endl;
    sptr.reset(new int[12]); it won't delete arra like delete [] so needed custom delete shown below
  cout<<"\n refene count"<<sptr.use_count()<<" p2 "<<p2.use_count()<<endl;

   void customDel(int x){
          delete[] x; // to delete array [] required so custom delete needs to be written
   }

  shared_ptr<int>p(new int[12], customDel);
   cout<<"\n refene count"<<sptr.use_count()<<" p "<<p.use_count()<<endl;
   sptr = nullptr; // other way to reset using null pointer same count will decrease by 1 and delete if count is 0
    cout<<"\n refene count"<<sptr.use_count()<<" p2 "<<p2.use_count()<<endl;


Notes for shared pointer:carefull
 - Try not to use same raw pointer for more than one shared_ptr objects.
    Ex: int *p = new int();
          shared_ptr<int>sp1(p);{
          shared_ptr<int>sp2(p);// wrong u not aware if sp2 goes out of scope then raw pointer deleted when sp1 goes out of scope then its a dangling pointer
         }
 - Don't create shared pointer from stack memory
      Ex: int x= 10;
             shared_ptr<int>spt2(&x); // &x is stack address when shared pointer goes out of scope then deleting stack memory using delete will crash the program

Week_ptr<>: weekpointer  allows sharing but not owns the object i.e not maintain reference count.
- circular dependency of shared object problem can be solved using the week pointer
Ex: Class A, class B objects maintain the class object in each other then reference count never comes to 0 if we use shared pointer.

15. Extensible random number facility
16. Wrapper reference std::ref()
17. Uniform method for computing the return type of function objects
18. Lambdas
19. non-member begin() and end()
20.

No comments:

Post a Comment

Port forwarding issues and port collusion by more then one process

Port forwarding script to identify collusions  Identifying local and remote port forwarding processes, as well as checking for potential col...