nullptr의 기초
std::nullptr_t
널 포인터 리터럴 인 nullptr의 유형입니다. 유형의 prvalue / rvalue입니다 std::nullptr_t
. nullptr에서 모든 포인터 유형의 널 포인터 값으로의 암시 적 변환이 있습니다.
리터럴 0은 포인터가 아닌 정수입니다. C ++이 포인터 만 사용할 수있는 컨텍스트에서 0을보고 있으면 0을 널 포인터로 간결하게 해석하지만 대체 위치입니다. C ++의 기본 정책은 0이 포인터가 아니라 int라는 것입니다.
장점 1-포인터 및 정수 유형에 과부하가 걸리는 경우 모호함 제거
C ++ 98에서 이것의 주된 의미는 포인터와 정수형에 과부하가 걸리면 놀라움을 줄 수 있다는 것입니다. 이러한 과부하에 0 또는 NULL을 전달하면 결코 포인터 과부하를 호출하지 않습니다.
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*)
이 호출에 대한 흥미로운 점은 소스 코드의 명백한 의미 ( "Null 포인터로 재미를 부르고 있습니다")와 실제 의미 ( "Null이 아닌 어떤 종류의 정수로 재미를 부르고 있습니다"라는 모순입니다. 바늘").
nullptr의 장점은 정수 유형이 없다는 것입니다. nullptr을 적분으로 볼 수 없기 때문에 nullptr로 오버로드 된 함수 fun을 호출하면 void * 오버로드 (예 : 포인터 오버로드)가 호출됩니다.
fun(nullptr); // calls fun(void*) overload
따라서 0 또는 NULL 대신 nullptr을 사용하면 과부하 해결 놀라움을 피할 수 있습니다.
의 또 다른 장점 nullptr
을 통해 NULL(0)
반환 형식에 대한 자동을 사용하는 경우
예를 들어, 코드베이스에서이 문제가 발생한다고 가정 해보십시오.
auto result = findRecord( /* arguments */ );
if (result == 0) {
....
}
findRecord가 무엇을 리턴하는지 알 수 없거나 쉽게 찾을 수없는 경우 결과가 포인터 유형인지 정수 유형인지 명확하지 않을 수 있습니다. 결국 0 (결과가 테스트 된 결과)은 어느 쪽이든 갈 수 있습니다. 반면에 다음을 보면
auto result = findRecord( /* arguments */ );
if (result == nullptr) {
...
}
모호성이 없습니다. 결과는 포인터 유형이어야합니다.
장점 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;
}
위의 프로그램은 성공적으로 컴파일되고 실행되었지만 lockAndCallF1, lockAndCallF2 & lockAndCallF3에는 중복 코드가 있습니다. 이러한 모든 템플릿을 작성할 수 있다면 이와 같은 코드를 작성하는 것이 유감 lockAndCallF1, lockAndCallF2 & lockAndCallF3
입니다. 따라서 템플릿으로 일반화 할 수 있습니다. 중복 코드에 대한 lockAndCall
다중 정의 대신 템플릿 기능을 작성했습니다 lockAndCallF1, lockAndCallF2 & lockAndCallF3
.
코드는 다음과 같이 리팩터링됩니다.
#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;
}
컴파일이 실패 이유를 상세 분석 lockAndCall(f1, f1m, 0) & lockAndCall(f3, f3m, nullptr)
을 위해하지lockAndCall(f3, f3m, nullptr)
왜 컴파일이 lockAndCall(f1, f1m, 0) & lockAndCall(f3, f3m, nullptr)
실패 했습니까?
문제는 lockAndCall에 0을 전달하면 템플릿 유형 공제가 유형을 파악하기 시작합니다. 0의 유형은 int이므로 lockAndCall에 대한이 호출의 인스턴스화 내에서 매개 변수 ptr의 유형입니다. 불행히도, 이것은 lockAndCall 내부의 func 호출에서 int가 전달되고 있으며 예상 되는 std::shared_ptr<int>
매개 변수 와 호환되지 않음을 의미합니다 f1
. 호출에 전달 된 0 lockAndCall
은 널 포인터를 나타 내기위한 것이지만 실제로 전달 된 것은 int입니다. 이 int를 f1에 전달하려고 std::shared_ptr<int>
하면 유형 오류가 발생합니다. lockAndCall
템플릿 내에서 int가을 (를) 요구하는 함수에 전달되어 0으로 호출이 실패합니다 std::shared_ptr<int>
.
관련된 통화에 대한 분석 NULL
은 본질적으로 동일합니다. NULL
에 전달 되면 lockAndCall
매개 변수 ptr에 대해 정수 유형이 추론되고 ptr
int 또는 int와 유사한 유형이에 전달 될 때 유형 오류가 발생 f2
하여를 얻을 것으로 예상합니다 std::unique_ptr<int>
.
반대로, 관련된 전화 nullptr
에는 문제가 없습니다. 시 nullptr
에 전달 lockAndCall
을 위해이 유형 ptr
추론되어있을 수 있습니다 std::nullptr_t
. ptr
로 전달 되면 f3
을 ( std::nullptr_t
를 int*
) std::nullptr_t
암시 적으로 모든 포인터 유형으로 변환하기 때문에 에서 (으) 로의 암시 적 변환이 있습니다.
널 포인터를 참조 할 때마다 0 또는가 아닌 nullptr을 사용하는 것이 좋습니다 NULL
.
int
하고void *
선택되지 않습니다int
오버 버전을void *
사용하는 경우 버전nullptr
.