Basics of nullptr
std::nullptr_t is the type of the null pointer literal, nullptr. It is a prvalue/rvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type.
The literal 0 is an int, not a pointer. If C++ finds itself looking at 0 in a context where only a pointer can be used, it’ll grudgingly interpret 0 as a null pointer, but that’s a fallback position. C++’s primary policy is that 0 is an int, not a pointer.
Advantage 1 - Remove ambiguity when overloading on pointer and integral types
In C++98, the primary implication of this was that overloading on pointer and integral types could lead to surprises. Passing 0 or NULL to such overloads never called a pointer overload:
   void fun(int); // two overloads of fun
    void fun(void*);
    fun(0); // calls f(int), not fun(void*)
    fun(NULL); // might not compile, but typically calls fun(int). Never calls fun(void*)
The interesting thing about that call is the contradiction between the apparent meaning of the source code (“I am calling fun with NULL-the null pointer”) and its actual meaning (“I am calling fun with some kind of integer— not the null pointer”).
nullptr’s advantage is that it doesn’t have an integral type.
Calling the overloaded function fun with nullptr calls the void* overload (i.e., the pointer overload), because nullptr can’t be viewed as anything integral:
fun(nullptr); // calls fun(void*) overload 
Using nullptr instead of 0 or NULL thus avoids overload resolution surprises. 
Another advantage of nullptr over NULL(0) when using auto for return type
For example, suppose you encounter this in a code base:
auto result = findRecord( /* arguments */ );
if (result == 0) {
....
}
If you don’t happen to know (or can’t easily find out) what findRecord returns, it may not be clear whether result is a pointer type or an integral type. After all, 0 (what result is tested against) could go either way. If you see the following, on the other hand,
auto result = findRecord( /* arguments */ );
if (result == nullptr) {
...
}
there’s no ambiguity: result must be a pointer type.
Advantage 3
#include<iostream>
#include <memory>
#include <thread>
#include <mutex>
using namespace std;
int f1(std::shared_ptr<int> spw) // call these only when
{
  //do something
  return 0;
}
double f2(std::unique_ptr<int> upw) // the appropriate
{
  //do something
  return 0.0;
}
bool f3(int* pw) // mutex is locked
{
return 0;
}
std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
using MuxtexGuard = std::lock_guard<std::mutex>;
void lockAndCallF1()
{
        MuxtexGuard g(f1m); // lock mutex for f1
        auto result = f1(static_cast<int>(0)); // pass 0 as null ptr to f1
        cout<< result<<endl;
}
void lockAndCallF2()
{
        MuxtexGuard g(f2m); // lock mutex for f2
        auto result = f2(static_cast<int>(NULL)); // pass NULL as null ptr to f2
        cout<< result<<endl;
}
void lockAndCallF3()
{
        MuxtexGuard g(f3m); // lock mutex for f2
        auto result = f3(nullptr);// pass nullptr as null ptr to f3 
        cout<< result<<endl;
} // unlock mutex
int main()
{
        lockAndCallF1();
        lockAndCallF2();
        lockAndCallF3();
        return 0;
}
Above program compile and executed successfully but lockAndCallF1, lockAndCallF2 & lockAndCallF3 have redundant code. It is pity to write code like this if we can write template for all these lockAndCallF1, lockAndCallF2 & lockAndCallF3. So it can be generalized with template. I have written template function lockAndCall instead of multiple definition lockAndCallF1, lockAndCallF2 & lockAndCallF3 for redundant code.   
Code is re-factored as below:
#include<iostream>
#include <memory>
#include <thread>
#include <mutex>
using namespace std;
int f1(std::shared_ptr<int> spw) // call these only when
{
  //do something
  return 0;
}
double f2(std::unique_ptr<int> upw) // the appropriate
{
  //do something
  return 0.0;
}
bool f3(int* pw) // mutex is locked
{
return 0;
}
std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
using MuxtexGuard = std::lock_guard<std::mutex>;
template<typename FuncType, typename MuxType, typename PtrType>
auto lockAndCall(FuncType func, MuxType& mutex, PtrType ptr) -> decltype(func(ptr))
//decltype(auto) lockAndCall(FuncType func, MuxType& mutex, PtrType ptr)
{
        MuxtexGuard g(mutex);
        return func(ptr);
}
int main()
{
        auto result1 = lockAndCall(f1, f1m, 0); //compilation failed 
        //do something
        auto result2 = lockAndCall(f2, f2m, NULL); //compilation failed
        //do something
        auto result3 = lockAndCall(f3, f3m, nullptr);
        //do something
        return 0;
}
Detail analysis why compilation failed for lockAndCall(f1, f1m, 0) & lockAndCall(f3, f3m, nullptr) not for lockAndCall(f3, f3m, nullptr)
Why compilation of lockAndCall(f1, f1m, 0) & lockAndCall(f3, f3m, nullptr) failed?
The problem is that when 0 is passed to lockAndCall, template type deduction kicks in to figure out its type. The type of 0 is int, so that’s the type of the parameter ptr inside the instantiation of this call to lockAndCall. Unfortunately, this means that in the call to func inside lockAndCall, an int is being passed, and that’s not compatible with the std::shared_ptr<int> parameter that f1 expects. The 0 passed in the call to lockAndCall was intended to represent a null pointer, but what actually got passed was int. Trying to pass this int to f1 as a std::shared_ptr<int> is a type error. The call to lockAndCall with 0 fails because inside the template, an int is being passed to a function that requires a std::shared_ptr<int>.
The analysis for the call involving NULL is essentially the same. When NULL is passed to lockAndCall, an integral type is deduced for the parameter ptr, and a type error occurs when ptr—an int or int-like type—is passed to f2, which expects to get a std::unique_ptr<int>.
In contrast, the call involving nullptr has no trouble. When nullptr is passed to lockAndCall, the type for ptr is deduced to be std::nullptr_t. When ptr is passed to f3, there’s an implicit conversion from std::nullptr_t to int*, because std::nullptr_t implicitly converts to all pointer types.
It is recommended, Whenever you want to refer to a null pointer, use nullptr, not 0 or NULL.