항목 1 : 포인터(pointer)와 참조자(reference)를 구분하자

참조하고자 하는 객체를 미리 알고 있을때

우선, 참조자 개념에선 “널 참조자(null reference)”란 없다. 참조자는 어떤 경우든지 메모리 공간을 차지한 객체를 참조하고 있어야 한다. 참조 하는 부분의 객체가 있지 않을 경우도 있다고 한다면, 주저 말고 참조자를 버리고 포인터를 쓰도록 한다.
하지만 아래와 같은 어처구니 없는 경우로 널을 참조하게 할 수도 있다. 이런 코드르 쓸 것이 걱정되면 아예 처음 부터 참조자 보기를 돌같이 하는게 낫다.

char *pc = 0; // 포인터를 널로 세팅 
char &rc = *pc; // 널을 참조하려는 시도
참조자는 반드시 선언될 때 반드시 초기화 되어야 한다.
string & rs; // 에러!! 참조자는 반드시 초기화 해야 한다.
string s("xyz"); 
string &rs = s;
포인터보다 참조자를 쓰는 것이 더 효율적일 수 있다.

C++에서 널 참조자가 존재하지 않는다는 것은 유효성 검사를 필요로 하지 않는다는 의미로 볼 수 있다.

void printDouble(const double &rd, const double *pd)
{
    if ( pd ) cout << *pd; // 널 포인터 검사를 해야한다. 
    cout << rd; // 널 객체를 참조하는지 볼 필요가 없다. 
}

다른 객체를 바꾸어 참조하는 일이 결코 없을 때

포인터는 다른 객체의 주소값으로 얼마든지 바꾸어 세팅 할 수 있지만, 참조자는 초기화될 때 참조 했던 그 객체만 참조한다.

string s1("Nancy");
string s2("Clancy"); 

string &rs= = s1; 
rs = s2; // rs는 여전히 s1을 가리키지만, s1의 값은 이제 "Clancy"이다. 

일반적으로, 포인터를 써야 하는 경우는 딱히 가리킬 객체의 주소가 없을 때이거나 하나의 변수를 가지고 여러 개의 객체를 바꾸어 참조해야 할 때이고, 그렇지 않고 참조 대상이 처음부터 끝까지 존재하고 객체를 바꿀 필요가 없을 때는 참조를 쓴다.

포인터를 사용하면 문법상 의미가 어색해 지는 연산자를 구현할 때

한가지 특수한 상황으로 연산자 함수를 구현 할 때 문법상 의미가 어색해 지는 경우 참조자를 반드시 써야 한다. 가능 흔한 예로 operator[]를 보면

vector<int> v(10); // 크기 10의 벡터를 만들고,
v[5] = 10; // operator[]의 반환값에 10을 대입한다. 이럴경우 참조자가 자연스럽다. 
// *v[5] = 10; // operator[]가 포인터를 반환한다면, 어색한 형태의 대입이 될 것이다. 

이 코드는 v가 실제로는 아니지만 포인터의 벡터인 것처럼 보이게 하는 단점을 가지고 있다. 때문에 이럴 때는 십중팔구 참조자를 반환해야 한다. ( 하지만 이 법칙에 대한 재미 있는 예외 상황이 하나 있는데, 항목 30을 참조 )