Pointer declaration
포인터 또는 멤버 포인터 타입의 변수를 선언합니다.
목차 |
구문
포인터 선언은 선언자 가 다음 형태를 갖는 모든 단순 선언입니다
*
attr
(선택 사항)
cv
(선택 사항)
declarator
|
(1) | ||||||||
nested-name-specifier
*
attr
(선택 사항)
cv
(선택 사항)
declarator
|
(2) | ||||||||
C
의 비정적 멤버에 대한 포인터로 선언하며, 그 타입은 선언 지정자 시퀀스
S
에 의해 결정됩니다.
| nested-name-specifier | - |
이름과 범위 확인 연산자들의
시퀀스
::
|
| attr | - | (since C++11) 속성들 의 목록 |
| cv | - | 선언되는 포인터에 적용되는 const/volatile 한정자 (지시되는 타입에 대한 한정자가 아니며, 그 한정자들은 선언 지정자 시퀀스의 일부임) |
| declarator | - | 임의의 선언자 |
참조 에 대한 포인터는 존재하지 않으며, 비트 필드 에 대한 포인터도 존재하지 않습니다. 일반적으로, 별도의 설명 없이 "포인터"라고 언급할 때는 (비정적) 멤버에 대한 포인터를 포함하지 않습니다.
포인터
모든 포인터 타입의 값은 다음 중 하나입니다:
- 객체나 함수에 대한 포인터 (이 경우 포인터가 해당 객체나 함수를 가리킨다 고 표현함), 또는
- 객체의 끝을 지난 포인터 , 또는
- 해당 타입의 null 포인터 값 , 또는
- 유효하지 않은 포인터 값 .
객체를 가리키는 포인터는 해당 객체가 메모리에서 차지하는 첫 번째 바이트의 주소를 나타냅니다. 객체의 끝을 지난 포인터는 해당 객체가 차지하는 저장 공간의 끝 이후 첫 번째 바이트의 주소를 나타냅니다.
동일한 주소를 나타내는 두 포인터가 그럼에도 다른 값을 가질 수 있음에 유의하십시오.
struct C { int x, y; } c; int* px = &c.x; // px의 값은 "c.x에 대한 포인터"입니다 int* pxe= px + 1; // pxe의 값은 "c.x의 끝을 지난 포인터"입니다 int* py = &c.y; // py의 값은 "c.y에 대한 포인터"입니다 assert(pxe == py); // ==는 두 포인터가 동일한 주소를 나타내는지 테스트합니다 // 발생할 수도 있고 발생하지 않을 수도 있습니다 *pxe = 1; // 어설션이 발생하지 않더라도 미정의 동작입니다
무효한 포인터 값을 통한 간접 참조 및 무효한 포인터 값을 할당 해제 함수에 전달하는 것은 정의되지 않은 동작을 유발합니다. 무효한 포인터 값의 다른 모든 사용은 구현에서 정의된 동작을 가집니다. 일부 구현에서는 무효한 포인터 값을 복사할 경우 시스템에서 생성된 런타임 오류가 발생하도록 정의할 수 있습니다.
객체에 대한 포인터
객체에 대한 포인터는 객체 타입의 표현식(다른 포인터 타입을 포함하여)에 적용된 주소 연산자 의 반환값으로 초기화될 수 있습니다:
int n; int* np = &n; // int에 대한 포인터 int* const* npp = &np; // non-const int에 대한 const 포인터를 가리키는 non-const 포인터 int a[2]; int (*ap)[2] = &a; // int 배열에 대한 포인터 struct S { int n; }; S s = {1}; int* sp = &s.n; // s의 멤버인 int를 가리키는 포인터
포인터는 내장 역참조 연산자(단항 operator * )의 피연산자로 나타날 수 있으며, 이는 가리키는 객체를 식별하는 lvalue expression 을 반환합니다:
int n; int* p = &n; // n을 가리키는 포인터 int& r = *p; // 참조자가 n을 식별하는 lvalue 표현식에 바인딩됨 r = 7; // n에 int 값 7을 저장 std::cout << *p; // lvalue-to-rvalue 암시적 변환이 n에서 값을 읽음
클래스 객체에 대한 포인터는 또한 멤버 접근 연산자
operator->
와
operator->*
의 좌측 피연산자로 나타날 수 있습니다.
배열-포인터 암시적 변환 때문에, 배열의 첫 번째 요소에 대한 포인터는 배열 타입의 표현식으로 초기화될 수 있습니다:
int a[2]; int* p1 = a; // 배열 a의 첫 번째 요소 a[0](int형)을 가리키는 포인터 int b[6][3][8]; int (*p2)[3][8] = b; // 배열 b의 첫 번째 요소 b[0]을 가리키는 포인터, // 이는 8개 int 원소를 가진 배열 3개로 구성된 배열임
파생 클래스-기반 클래스 포인터에 대한 암시적 변환 때문에, 기반 클래스에 대한 포인터는 파생 클래스의 주소로 초기화될 수 있습니다:
struct Base {}; struct Derived : Base {}; Derived d; Base* p = &d;
만약
Derived
가
다형적(polymorphic)
이라면, 이러한 포인터를 사용하여
가상 함수 호출(virtual function calls)
을 수행할 수 있습니다.
특정 덧셈, 뺄셈 , 증가, 감소 연산자들은 배열 요소에 대한 포인터에 대해 정의됩니다: 이러한 포인터들은 LegacyRandomAccessIterator 요구 사항을 충족하며 C++ 라이브러리 알고리즘들 이 원시 배열들과 함께 동작할 수 있도록 합니다.
비교 연산자 는 객체에 대한 포인터에 대해 특정 상황에서 정의됩니다: 동일한 주소를 나타내는 두 포인터는 동등하게 비교되고, 두 널 포인터 값은 동등하게 비교되며, 동일한 배열의 요소에 대한 포인터는 해당 요소들의 배열 인덱스와 동일하게 비교되고, 동일한 멤버 접근 권한 을 가진 비정적 데이터 멤버에 대한 포인터는 해당 멤버들의 선언 순서대로 비교됩니다.
많은 구현에서는 또한 임의 출처의 포인터에 대한 엄격한 전체 순서 를 제공합니다. 예를 들어 연속적인 가상 주소 공간 내의 주소로 구현된 경우가 있습니다. 이를 제공하지 않는 구현(예: 포인터의 모든 비트가 메모리 주소의 일부가 아니어서 비교 시 무시해야 하거나, 추가 계산이 필요하거나, 그렇지 않으면 포인터와 정수가 1대1 관계가 아닌 경우)의 경우, 해당 보장을 갖는 포인터에 대한 std::less 의 특수화를 제공합니다. 이를 통해 임의 출처의 모든 포인터를 std::set 이나 std::map 과 같은 표준 연관 컨테이너의 키로 사용할 수 있습니다.
void 포인터
모든 타입의 객체에 대한 포인터는 (가능한
cv-qualified
)
void
포인터로
암시적으로 변환
될 수 있습니다; 포인터 값은 변경되지 않습니다. 역변환은
static_cast
또는
명시적 캐스트
가 필요하며, 원본 포인터 값을 반환합니다:
int n = 1; int* p1 = &n; void* pv = p1; int* p2 = static_cast<int*>(pv); std::cout << *p2 << '\n'; // 1을 출력함
원본 포인터가 다형성 타입의 객체 내에서 기본 클래스 하위 객체를 가리키는 경우,
dynamic_cast
를 사용하여 가장 파생된 타입의 완전한 객체를 가리키는
void
*
를 얻을 수 있습니다.
void 에 대한 포인터는 char 에 대한 포인터와 동일한 크기, 표현 방식 및 정렬 방식을 가집니다.
void에 대한 포인터는 알려지지 않은 타입의 객체를 전달하는 데 사용되며, 이는 C 인터페이스에서 흔히 볼 수 있습니다:
void
는
std::malloc
이
void
*
를 반환하고,
std::qsort
는 두 개의
const
void
*
인수를 받는 사용자 제공 콜백을 기대합니다.
pthread_create
는
void
*
를 받고 반환하는 사용자 제공 콜백을 기대합니다. 모든 경우에, 사용 전에 포인터를 올바른 타입으로 캐스팅하는 것은 호출자의 책임입니다.
함수 포인터
함수에 대한 포인터는 비멤버 함수 또는 정적 멤버 함수의 주소로 초기화할 수 있습니다. 함수-포인터 변환 암시적 변환으로 인해 주소 연산자는 선택 사항입니다:
void f(int); void (*p1)(int) = &f; void (*p2)(int) = f; // &f와 동일함
함수나 함수에 대한 참조와 달리, 함수에 대한 포인터는 객체이므로 배열에 저장하거나, 복사하거나, 할당하는 등의 작업을 수행할 수 있습니다.
void (a[10])(int); // 오류: 함수 배열 void (&a[10])(int); // 오류: 참조 배열 void (*a[10])(int); // 정상: 함수 포인터 배열
참고: 함수 포인터를 포함하는 선언은 종종 타입 별칭을 사용하여 단순화할 수 있습니다:
using F = void(int); // 선언을 단순화하기 위한 명명된 타입 별칭 F a[10]; // 오류: 함수 배열 F& a[10]; // 오류: 참조 배열 F* a[10]; // 정상: 함수 포인터 배열
함수에 대한 포인터는 함수 호출 연산자 의 왼쪽 피연산자로 사용될 수 있으며, 이는 가리키는 함수를 호출합니다:
int f(int n) { std::cout << n << '\n'; return n * n; } int main() { int (*p)(int) = f; int x = p(7); }
함수 포인터를 역참조하면 가리키는 함수를 식별하는 lvalue가 생성됩니다:
int f(); int (*p)() = f; // 포인터 p가 f를 가리킴 int (&r)() = *p; // f를 식별하는 lvalue가 참조에 바인딩됨 r(); // lvalue 참조를 통해 함수 f 호출 (*p)(); // 함수 lvalue를 통해 함수 f 호출 p(); // 포인터를 직접 통해 함수 f 호출
함수 포인터는 오버로드 집합에서 초기화될 수 있으며, 이 집합에는 함수, 함수 템플릿 특수화 및 함수 템플릿이 포함될 수 있습니다. 단, 오직 하나의 오버로드만 포인터 타입과 일치하는 경우에 한합니다(자세한 내용은 address of an overloaded function 참조):
template<typename T> T f(T n) { return n; } double f(double n) { return n; } int main() { int (*p)(int) = f; // f<int>를 인스턴스화하고 선택함 }
동등 비교 연산자 는 함수 포인터에 대해 정의됩니다(동일한 함수를 가리킬 경우 동등으로 비교됩니다).
멤버 포인터
데이터 멤버에 대한 포인터
비정적 멤버 객체
m
에 대한 포인터는 클래스
C
의 멤버이며
&
C
::
m
표현식으로 정확히 초기화될 수 있습니다.
&
(
C
::
m
)
또는
&
m
와 같은 표현식은
C
의 멤버 함수 내에서도 멤버 포인터를 형성하지 않습니다.
이러한 포인터는 멤버 접근 연산자 operator. * 와 operator - > * 의 우측 피연산자로 사용될 수 있습니다:
접근 가능하고 모호하지 않은 비가상 기반 클래스의 데이터 멤버에 대한 포인터는 암시적으로 변환될 수 있습니다 파생 클래스의 동일한 데이터 멤버에 대한 포인터로:
struct Base { int m; }; struct Derived : Base {}; int main() { int Base::* bp = &Base::m; int Derived::* dp = bp; Derived d; d.m = 1; std::cout << d.*dp << ' ' << d.*bp << '\n'; // 1 1을 출력합니다 }
파생 클래스의 데이터 멤버 포인터에서 명확한 비가상 기반 클래스의 데이터 멤버 포인터로의 반대 방향 변환은
static_cast
와
명시적 캐스트
를 사용하여 허용됩니다. 심지어 기반 클래스가 해당 멤버를 가지고 있지 않은 경우에도(단, 포인터가 접근에 사용될 때 최종 파생 클래스는 해당 멤버를 가집니다):
멤버 포인터가 가리키는 타입은 그 자체로 또 다른 멤버 포인터일 수 있습니다: 멤버 포인터는 다중 레벨을 가질 수 있으며, 각 레벨마다 서로 다른 cv 한정자를 가질 수 있습니다. 포인터와 멤버 포인터가 혼합된 다중 레벨 조합도 허용됩니다:
struct A { int m; // const pointer to non-const member int A::* const p; }; int main() { // non-const pointer to data member which is a const pointer to non-const member int A::* const A::* p1 = &A::p; const A a = {1, &A::m}; std::cout << a.*(a.*p1) << '\n'; // 1을 출력 // regular non-const pointer to a const pointer-to-member int A::* const* p2 = &a.p; std::cout << a.**p2 << '\n'; // 1을 출력 }
멤버 함수 포인터
비정적 멤버 함수에 대한 포인터
f
는 클래스
C
의 멤버이며, 정확히
&
C
::
f
표현식으로 초기화할 수 있습니다.
&
(
C
::
f
)
또는
&
f
와 같은 표현식은
C
의 멤버 함수 내부에서도 멤버 함수에 대한 포인터를 형성하지 않습니다.
이러한 포인터는 멤버 접근 연산자 operator. * 와 operator - > * 의 우측 피연산자로 사용될 수 있습니다. 결과 표현식 은 함수 호출 연산자의 좌측 피연산자로만 사용될 수 있습니다:
struct C { void f(int n) { std::cout << n << '\n'; } }; int main() { void (C::* p)(int) = &C::f; // 클래스 C의 멤버 함수 f에 대한 포인터 C c; (c.*p)(1); // 1을 출력 C* cp = &c; (cp->*p)(2); // 2를 출력 }
기본 클래스의 멤버 함수에 대한 포인터는
암시적으로 변환될 수 있습니다
파생 클래스의 동일한 멤버 함수에 대한 포인터로:
struct Base { void f(int n) { std::cout << n << '\n'; } }; struct Derived : Base {}; int main() { void (Base::* bp)(int) = &Base::f; void (Derived::* dp)(int) = bp; Derived d; (d.*dp)(1); (d.*bp)(2); }
역방향 변환, 즉 파생 클래스의 멤버 함수 포인터에서 모호하지 않은 비가상 기본 클래스의 멤버 함수 포인터로의 변환은
static_cast
와
명시적 캐스트
를 사용하여 허용됩니다. 심지어 기본 클래스에 해당 멤버 함수가 없더라도 (단, 포인터를 사용하여 접근할 때 최종 파생 클래스가 해당 멤버 함수를 가지는 경우) 가능합니다:
struct Base {}; struct Derived : Base { void f(int n) { std::cout << n << '\n'; } }; int main() { void (Derived::* dp)(int) = &Derived::f; void (Base::* bp)(int) = static_cast<void (Base::*)(int)>(dp); Derived d; (d.*bp)(1); // 정상: 1을 출력함 Base b; (b.*bp)(2); // 정의되지 않은 동작 }
멤버 함수에 대한 포인터는 콜백이나 함수 객체로 사용될 수 있으며, 종종 std::mem_fn 또는 std::bind 를 적용한 후에 사용됩니다:
#include <algorithm> #include <cstddef> #include <functional> #include <iostream> #include <string> int main() { std::vector<std::string> v = {"a", "ab", "abc"}; std::vector<std::size_t> l; transform(v.begin(), v.end(), std::back_inserter(l), std::mem_fn(&std::string::size)); for (std::size_t n : l) std::cout << n << ' '; std::cout << '\n'; }
출력:
1 2 3
널 포인터
모든 타입의 포인터는 해당 타입의 null 포인터 값 이라고 알려진 특별한 값을 가집니다. 값이 null인 포인터는 객체나 함수를 가리키지 않으며(null 포인터를 역참조하는 동작은 정의되지 않음), 값이 동일하게 null 인 동일한 타입의 모든 포인터와 동등하게 비교됩니다.
null pointer constant 는 포인터를 null로 초기화하거나 기존 포인터에 null 값을 할당하는 데 사용할 수 있으며, 다음 값 중 하나입니다:
- 값이 0인 정수 리터럴.
|
(C++11부터) |
매크로 NULL 또한 사용할 수 있으며, 이는 구현에서 정의된 널 포인터 상수로 확장됩니다.
Zero-initialization 와 value-initialization 또한 포인터를 널 값으로 초기화합니다.
널 포인터는 객체의 부재를 나타내는 데 사용될 수 있습니다(예: std::function::target() ), 또는 다른 오류 조건 표시자로 사용될 수 있습니다(예: dynamic_cast ). 일반적으로, 포인터 인수를 받는 함수는 거의 항상 값이 널인지 확인하고 해당 경우를 다르게 처리해야 합니다(예를 들어, delete expression 은 널 포인터가 전달될 때 아무 작업도 수행하지 않습니다).
무효 포인터
포인터 값 p 가 평가 e 의 맥락에서 유효하다는 것은 다음 조건 중 하나가 충족될 때를 말합니다:
- p 는 널 포인터 값입니다.
- p 는 함수 포인터입니다.
- p 가 객체 o 의 끝 또는 그 너비를 가리키는 포인터이고, e 가 o 의 저장 영역 수명 주기 내에 있는 경우입니다.
만약 포인터 값 p 가 평가 e 에서 사용되고, p 가 e 의 컨텍스트에서 유효하지 않다면:
int* f() { int obj; int* local_ptr = new (&obj) int; *local_ptr = 1; // OK, 평가 "*local_ptr"은 // "obj"의 저장 기간 내에 있음 return local_ptr; } int* ptr = f(); // "obj"의 저장 기간이 만료되었으므로, // "ptr"은 다음 문맥에서 유효하지 않은 포인터임 int* copy = ptr; // 구현 정의 동작 *ptr = 2; // 정의되지 않은 동작: 유효하지 않은 포인터의 역참조 delete ptr; // 정의되지 않은 동작: 유효하지 않은 포인터로부터 저장 공간 해제
상수성
-
만약
cv
가 포인터 선언에서
*앞에 나타나면, 이는 선언 지정자 시퀀스의 일부이며 포인팅되는 객체에 적용됩니다. -
만약
cv
가 포인터 선언에서
*뒤에 나타나면, 이는 선언자 의 일부이며 선언되는 포인터 자체에 적용됩니다.
| 구문 | 의미 |
|---|---|
| const T * | 상수 객체에 대한 포인터 |
| T const * | 상수 객체에 대한 포인터 |
| T * const | 객체에 대한 상수 포인터 |
| const T * const | 상수 객체에 대한 상수 포인터 |
| T const * const | 상수 객체에 대한 상수 포인터 |
// pc는 const int에 대한 비-const 포인터입니다 // cpc는 const int에 대한 const 포인터입니다 // ppc는 const int에 대한 비-const 포인터에 대한 비-const 포인터입니다 const int ci = 10, *pc = &ci, *const cpc = pc, **ppc; // p는 비-const int에 대한 비-const 포인터입니다 // cp는 비-const int에 대한 const 포인터입니다 int i, *p, *const cp = &i; i = ci; // 정상: const int의 값이 비-const int로 복사됨 *cp = ci; // 정상: const 포인터가 가리키는 비-const int는 변경 가능 pc++; // 정상: const int에 대한 비-const 포인터는 변경 가능 pc = cpc; // 정상: const int에 대한 비-const 포인터는 변경 가능 pc = p; // 정상: const int에 대한 비-const 포인터는 변경 가능 ppc = &pc; // 정상: const int에 대한 포인터의 주소는 const int에 대한 포인터에 대한 포인터임 ci = 1; // 오류: const int는 변경할 수 없음 ci++; // 오류: const int는 변경할 수 없음 *pc = 2; // 오류: 가리키는 const int는 변경할 수 없음 cp = &ci; // 오류: 비-const int에 대한 const 포인터는 변경할 수 없음 cpc++; // 오류: const int에 대한 const 포인터는 변경할 수 없음 p = pc; // 오류: 비-const int에 대한 포인터는 const int를 가리킬 수 없음 ppc = &p; // 오류: const int에 대한 포인터에 대한 포인터는 // 비-const int에 대한 포인터를 가리킬 수 없음
일반적으로, 한 다단계 포인터에서 다른 다단계 포인터로의 암시적 변환은 qualification conversions 에 설명된 규칙을 따릅니다.
복합 포인터 타입
비교 연산자의 피연산자 또는 조건부 연산자 의 두 번째와 세 번째 피연산자 중 하나가 포인터나 멤버 포인터일 때, 이러한 피연산자들의 공통 타입으로 복합 포인터 타입이 결정됩니다.
두 개의 피연산자
p1
와
p2
가 각각
T1
과
T2
타입을 가질 때,
p1
과
p2
는 다음 조건 중 하나를 만족하는 경우에만 복합 포인터 타입을 가질 수 있습니다:
|
(C++14 이전) | ||
|
(C++14부터) |
복합 포인터 타입
C
는
p1
과
p2
에 대해 다음과 같이 결정됩니다:
|
(C++11 이전) |
|
(C++11 이후) |
- 그렇지 않고, 다음 조건들이 모두 충족되는 경우:
-
-
T1또는T2가 " cv1 void 에 대한 포인터"인 경우. -
다른 타입이 "
cv2
T에 대한 포인터"이며, 여기서T는 객체 타입 또는 void 인 경우.
-
-
C는 " cv12 void 에 대한 포인터"이며, 여기서 cv12 는 cv1 과 cv2 의 결합입니다.
|
(C++17부터) |
- 그렇지 않고, 다음 조건들이 모두 충족되는 경우:
-
-
T1은 "C1에 대한 포인터"입니다. -
T2은 "C2에 대한 포인터"입니다. -
C1과C2중 하나가 다른 하나와 참조 관련(reference-related) 입니다.
-
-
C는-
C1이C2와 참조 관련일 경우T1과T2의 한정자 결합 타입(qualification-combined type) 이거나, -
C2가C1과 참조 관련일 경우T2와T1의 한정자 결합 타입입니다.
-
|
(C++17부터) |
- 그렇지 않고, 다음 조건들이 모두 충족되는 경우:
-
-
T1은 "비함수 타입M1의C1멤버 포인터"입니다. -
T2은 "비함수 타입M2의C2멤버 포인터"입니다. -
M1과M2는 최상위 cv-한정자를 제외하고 동일합니다. -
C1과C2중 하나가 다른 하나에 대해 참조 관련(reference-related)입니다.
-
-
C는-
C1이C2에 참조 관련된 경우T2와T1의 자격 결합(qualification-combined) 타입, 또는 -
C2이C1에 참조 관련된 경우T1과T2의 자격 결합 타입입니다.
-
-
그렇지 않고
T1과T2가 유사 타입(similar types) 인 경우,C는T1과T2의 한정자 결합 타입(qualification-combined type)입니다. -
그렇지 않은 경우,
p1
과
p2
는 복합 포인터 타입(composite pointer type)을 가지지 않으며,
C와 같은 타입의 결정을 필요로 하는 프로그램은 형식이 잘못되었습니다(ill-formed).
using p = void*; using q = const int*; // "p"와 "q"의 복합 포인터 타입 결정은 // ["cv1 void에 대한 포인터"와 "cv2 T에 대한 포인터"] 경우에 해당함: // cv1 = 비어있음, cv2 = const, cv12 = const // "cv12 = const"를 "cv12 void에 대한 포인터"에 대입: // 복합 포인터 타입은 "const void*" using pi = int**; using pci = const int**; // "pi"와 "pci"의 복합 포인터 타입 결정은 // [유사한 타입 "C1"과 "C2"에 대한 포인터] 경우에 해당함: // C1 = int*, C2 = const int* // 이들은 유사한 타입이므로 참조 관련 타입임(양방향) // 복합 포인터 타입은 "p1"과 "pc1"의 // 자격 결합 타입(또는 "pci"와 "pi"의 자격 결합 타입): "const int**"
결함 보고서
다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.
| DR | 적용 대상 | 게시된 동작 | 올바른 동작 |
|---|---|---|---|
| CWG 73 | C++98 |
객체에 대한 포인터는 배열의 끝을 지난 위치에 대한 포인터와
절대 같다고 비교되지 않음 |
널이 아니고 함수 포인터가 아닌 경우,
나타내는 주소를 비교함 |
| CWG 903 | C++98 |
0으로 평가되는 모든 정수 상수 표현식이
널 포인터 상수였음 |
값이 0인 정수
리터럴로 제한됨 |
| CWG 1438 | C++98 |
유효하지 않은 포인터 값을 어떤 방식으로든
사용하는 동작은 정의되지 않음 |
역참조 및 할당 해제 함수에 전달하는 것 외의
동작들은 구현에서 정의됨 |
|
CWG 1512
( N3624 ) |
C++98 |
복합 포인터 타입 규칙이 불완전하여
int ** 와 const int ** 사이의 비교를 허용하지 않음 |
완전하게 만듦 |
| CWG 2206 | C++98 |
void
에 대한 포인터와 함수에 대한 포인터가
복합 포인터 타입을 가짐 |
이러한 타입을 가지지 않음 |
| CWG 2381 | C++17 |
복합 포인터 타입을 결정할 때 함수 포인터 변환이
허용되지 않음 |
허용됨 |
| CWG 2822 | C++98 |
저장 영역의 지속 기간이 끝나면 포인터 값이
무효화될 수 있음 |
포인터 유효성은
평가 컨텍스트에 기반함 |
| CWG 2933 | C++98 | 함수에 대한 포인터는 항상 유효하지 않음 | 항상 유효함 |
참고 항목
|
C documentation
for
Pointer declaration
|