Modern C++ - nullptr


#include <iostream>

#include <vector>

#include <list>

#include <deque>

#include <map>

#include <set>

#include<algorithm>

using namespace std;

// Modern C++ (C++11 부터 나온 아이들)

// nullptr

class Knight {

public:

 void Test() {

 cout << "Knight::Test()" << endl;

 }

};

Knight* FindKnight() {

 //TODO

 return nullptr;

}

void Test(int a) {

 cout << "Test(int)" << endl;

}

void Test(int* a) {

 cout << "Test(int*)" << endl;

}

// NullPtr 구현

class NullPtr{

public:

 // 그 어떤 데이터형의 포인터든 호환이 된다~

 template<typename T>

 operator T* () const {

 return 0;

 }

 // 그 어떤 타입의 멤버 포인터와도 치환 가능

 template<typename C, typename T>

 operator T C::* () const {

 return 0;

 }

private :

 // 주소값을 꺼내오려할 경우 private이므로 접근 거부됨

 void operator&() const; //주소값 &을 막는다.

 //void operator&() const = delete; //주소값 &을 막는다.

}_nullptr;

template<typename T>

struct Func{

public:

};

int main()

{

 // nullptr이 없던 때에는 0 or NULL로 표현함

 // nullptr을 사용해도 실제로는 0이 들어가서 상관 없긴 함, 

 // 또 0이 너무 정수같은 느낌이라 가독성을 위해 NULL을 사용해도 상관 없음

 // 문제는 포인터와 정수를 모두 받도록 오버로딩된 함수가 있을 경우

 // 0과 NULL을 인자값으로 줄 경우 무조건 포인터가 아닌 정수로 인식한다는 것

 Test(0);

 Test(NULL); // 둘다 모두 Test(int)를 실행한다는 것을 알 수 있다.

 // 이러한 문제를 해결하기 위해 nullptr을 추가하였다.

 Test(nullptr);

 // nullptr을 사용하는 이유: 오작동 방지!

 auto knight = FindKnight();

 // 실제로는 nullptr과 비교하는 비교문이지만

 // auto를 사용했기 때문에 제 3자가 봤을 때 0의 의미가 

 // int 0인지 nullptr인지 빠르게 유추하기 어렵다

 if (knight == 0) {

 }

 // nullptr을 사용할 경우 바로 알아차릴 수 있다.

 if (knight == _nullptr) {

 }

 nullptr_t whoami = nullptr;

 Knight* k2 = _nullptr;

 void (Knight:: * memFunc)();

 

 memFunc = &Knight::Test;

 if (memFunc == _nullptr) {

 }

 

 // 결론 null 포인터가 필요할 때 0과 NULL을 사용하는 대신 nullptr을 사용하자!

 return 0;

}