const 포인터의 요점은 무엇입니까?


149

const 값에 대한 포인터가 아니라 const 포인터 자체에 대해 이야기하고 있습니다.

나는 매우 기본적인 것들을 넘어서 C와 C ++를 배우고 있으며 오늘까지 포인터가 함수에 가치에 의해 전달된다는 것을 깨달았습니다. 이것은 함수 내에서 호출자의 원래 포인터에 영향을 미치지 않고 복사 된 포인터가 다른 값을 가리 키도록 할 수 있음을 의미합니다.

따라서 함수 헤더가 갖는 요점은 무엇입니까?

void foo(int* const ptr);

그러한 함수 안에서는 ptr이 const이기 때문에 다른 것을 가리킬 수 없으며 수정하기를 원하지 않지만 다음과 같은 함수는 다음과 같습니다.

void foo(int* ptr);

작업도 마찬가지입니다! 어쨌든 포인터가 복사되고 사본을 수정하더라도 호출자의 포인터는 영향을받지 않기 때문입니다. const의 장점은 무엇입니까?


29
컴파일 타임에 포인터가 다른 것을 가리 키도록 수정할 수 없으며 수정해서는 안된다는 것을 보장하려면 어떻게해야합니까?
Platinum Azure

25
모든 const매개 변수 와 정확히 같은 점 입니다.
David Heffernan

2
@PlatinumAzure, 몇 년 동안 프로그래밍 경험이 있지만 소프트웨어 관행이 부족합니다. 컴파일러가 내 자신의 논리 오류를 지적 할 필요성을 느끼지 못했기 때문에이 질문을 한 것이 기쁩니다. 질문을 제출 한 순간의 초기 반응은 "포인터가 수정되면 왜 신경 써야합니까? 그것은 호출자에게 영향을 미치지 않습니다"였습니다. 내가 모든 답변을 읽을 때까지 나는 그것을 수정하려고하면 나와 코딩 논리가 잘못되었거나 별표가 누락 된 오타가 있었기 때문에주의해야한다는 것을 이해했으며 컴파일러가 ' 말 하지마
R. Ruiz.

3
@ R.Ruiz. 의심 할 여지없이, 우리 중 가장 경험이 많은 사람들도 정확성을 추가로 보장 할 수 있습니다. 소프트웨어 엔지니어링은 약간의 여유가 허용되는 엔지니어링 형태이기 때문에 (임의의 HTTP 502, 느린 연결, 가끔로드되지 않는 이미지는 특별한 경우는 아니지만 비행기에서 실패한 엔진은 받아 들일 수없고 심각 할 수 있음) 사람들은 과도한 서둘러 프로그램을합니다. 단위 테스트 작성을 정당화하는 동일한 주장은 const-correctness 보장 의 사용을 설명합니다 . 코드가 정확하다는 것을 더 확실하게 느끼게합니다.
Platinum Azure

답변:


207

const 매우 중요한 C ++ 개념을 추구하는 데 사용해야하는 도구입니다.

컴파일러가 의미하는 바를 적용하도록하여 런타임이 아닌 컴파일 타임에 버그를 찾으십시오.

기능이 변경되지 않더라도 추가를 const하면 의도하지 않은 작업을 수행 할 때 컴파일러 오류가 발생합니다. 다음 오타를 상상해보십시오.

void foo(int* ptr)
{
    ptr = 0;// oops, I meant *ptr = 0
}

을 사용 int* const하면 값을로 변경하기 때문에 컴파일러 오류가 발생합니다 ptr. 일반적으로 구문을 통해 제한을 추가하는 것이 좋습니다. 너무 많이 들지 마십시오. 예를 들어 대부분의 사람들이 귀찮게하지 않는 경우 const입니다.


8
감사합니다. 이것이 저를 설득시키는 답변입니다. 컴파일러가 자신의 할당 오류에 대해 경고하도록 const를 넣습니다. 이 개념은 포인터와의 일반적인 실수 이므로이 개념을 설명하기에 완벽합니다. 당신보다!
R. Ruiz.

25
"컴파일러가 당신을 도울 수 있도록 도와주세요"는 내가 일반적으로 부르는 만트라입니다.
Flexo

1
+1, 그러나 여기에 논쟁의 여지가있는 흥미로운 사례가 있습니다 : stackoverflow.com/questions/6305906/…
Raedwald

3
따라서 "클래스 외부에서 변수를 사용할 수 없을 때 변수를 비공개로 만드는 이유"와 동일한 대답입니다.
Lee Louviere

이것은 약간 벗어난 주제 일 수 있지만이 const 포인터는 메모리에 어디에 있습니까? 모든 const가 메모리의 전역 부분에 있다는 것을 알고 있지만 func var로 전달되는 const에 대해서는 100 % 확신하지 못합니다. 주제와 관련이없는 경우 감사와 미안
Tomer

77

더 많은 컴파일러 검사를 가능하게하기 때문에 인수 사용한다는 점을 지적 const합니다. 실수로 함수 내부에서 인수 값을 실수로 다시 할당하면 컴파일러가 물립니다.

나는 변수를 거의 재사용하지 않고 새로운 값을 보유하기 위해 새로운 변수를 만드는 것이 더 깨끗합니다. 따라서 본질적으로 모든 변수 선언은 다음 const과 같습니다 (루프 변수와 같은 일부 경우 제외)const 코드가 작동하지 못하게하는 )입니다.

이것은 함수 정의 에서만 의미 가 있습니다. 그것은 사용자에게 보이는 선언 에 속하지 않습니다 . 그리고 사용자는 내가 사용하는지 신경 쓰지 않습니다.const 함수 내부의 매개 변수에 .

예:

// foo.h
int frob(int x);
// foo.cpp
int frob(int const x) {
   MyConfigType const config = get_the_config();
   return x * config.scaling;
}

인수와 지역 변수가 모두 어떻게되는지 확인하십시오 const. 없는 둘 필요 하지만, 조금이라도 큰 기능이 반복적으로 실수에서 저를 저장하고있다.


17
+1다른- const집착 광신자 로부터 . 그러나 나는 내 컴파일러가 나에게 짖는 것을 선호한다. 나는 너무 많은 실수를 저지르고 그들이 물지 않을 것입니다.
sbi

2
+1, " const좋은 이유가 없다면"전략을 강력히 추천합니다 . 복사와 스왑
Flexo

2
새 언어를 디자인하는 경우 선언 된 객체는 기본적으로 읽기 전용 ( "const")입니다. 객체를 쓰기 가능하게하려면 특별한 구문, 아마도 "var"키워드가 필요합니다.
Keith Thompson

@Keith“물론”이라고 말하고 싶은 유혹이 있습니다. 이 시점에서 다른 모든 것은 바보입니다. 그러나 불행히도 대부분의 언어 디자이너들은 우리의 의견에 동의하지 않는 것 같습니다… 사실, 나는 이미 많은 글을 올렸습니다 (이제 삭제 된 질문에서“가장 논란이 많은 프로그래밍 의견은 무엇입니까?”).
Konrad Rudolph

1
@ KubaOber 어떻게 비관적인지 모르겠습니다. 나중에 함수 본문 내에서 전달 된 내용을 수정해야하는 const경우 인수에서 해당 항목을 삭제하고 이유를 설명하십시오. 약간의 추가 작업만으로도 모든 인수를 const기본적 으로 비논리로 표시 하고 발생할 수있는 모든 오류가 발생하는 것으로 정당화되는 것은 아닙니다 .
underscore_d

20

당신의 질문은 좀 더 일반적인 것을 만집니다 : 함수 인수는 const이어야합니까?

포인터와 같은 값 인수의 constness는 구현 세부 사항 이며 함수 선언의 일부를 형성 하지 않습니다 . 이것은 당신의 기능이 항상 이것임을 의미합니다 :

void foo(T);

함수 범위 인수 변수를 가변 또는 일정한 방식으로 사용하고자하는지 여부 는 전적으로 함수 구현 자 에게 달려 있습니다.

// implementation 1
void foo(T const x)
{
  // I won't touch x
  T y = x;
  // ...
}

// implementation 2
void foo(T x)
{
  // l33t coding skillz
  while (*x-- = zap()) { /* ... */ }
}

따라서 간단한 규칙 const에 따라 선언 (헤더)에 넣지 말고 변수를 수정하지 않으려는 경우 정의 (구현)에 넣으십시오.


5
나는 이것에 동의하지만 선언과 정의를 다르게 만드는 아이디어에 다소 불편하다. 이외의 경우 const, 선언과 정의의 프로토 타입 부분은 일반적으로 동일합니다.
Keith Thompson

@ KeithThompson : 글쎄, 당신이 원하지 않는다면 그것을 할 필요가 없습니다. const선언에 넣지 마십시오 . 구현에 한정자를 추가하려는 경우 전적으로 귀하에게 달려 있습니다.
Kerrek SB

1
내가 말했듯이, 나는 const선언을했지만 정의가 아니라는 것에 동의합니다 . 그것은 선언과 정의를 동일하지 않은 것이 의미가있는 유일한 경우라는 언어의 결함처럼 느껴집니다. (물론 C의 유일한 결함은 아닙니다.)
Keith Thompson

16

최상위 const 한정자는 선언에서 삭제되므로 질문의 선언은 정확히 동일한 함수를 선언합니다. 반면, 정의 (구현)에서 컴파일러는 포인터를 const로 표시하면 함수 본문 내에서 수정되지 않았는지 확인합니다.


나는 몰랐다. 따라서 void foo (int * t ptr)로 void foo (int * const ptr)를 오버로드하려고하면 컴파일러 오류가 발생합니다. 감사!
R. Ruiz.

@ R.Ruiz. 감속이 void foo (int * t ptr)이고 정의가 void foo (int * const ptr) 인 경우 컴파일러 오류가 발생하지 않습니다.
Trevor Hickey

1
@TrevorHickey 그들은 ...하지만 그들이 생각하는 이유가 아닙니다. int* t ptr구문 오류입니다. 이것이 없으면 두 가지가 오버로드 목적으로 동일합니다.
underscore_d

14

당신이 옳습니다. 발신자에게는 전혀 차이가 없습니다. 그러나 함수 작성자에게는 안전망이 될 수 있습니다. "알겠습니다.이 점을 잘못 지적하지 않아야합니다." 매우 유용하지는 않지만 쓸모가 없습니다.

기본적으로 int const the_answer = 42프로그램에 있는 것과 같습니다 .


1
그들이 가리키는 위치는 무엇이 중요합니까, 그것은 스택에 할당 된 포인터입니까? 함수는 그것을 망칠 수 없습니다. 포인터-포인터를 다룰 때 읽기 전용 포인터를 사용하는 것이 훨씬 더 합리적입니다. 그것은 것입니다 하지 INT const를 같은 것! 나는 그 오해의 소지가있는 진술을 위해 이것을 하향 투표 할 것이다. const intint const동일, 동안 const int*int* const두 개의 서로 다른 의미를 가지고!
Lundin

1
@lundin 함수가 크고 다른 것들이 있다고 가정 해 봅시다. 실수로 (함수 스택에서) 다른 것을 가리킬 수 있습니다. 이것은 발신자에게는 문제가되지 않지만 확실히 수신자에게는 문제가 될 수 있습니다. 나는 " 함수 작성자 에게는 안전망이 될 수있다 "라는 잘못된 진술을하지 않았다 .
cnicutar

1
정보 @Lundin int const부분; 나는 한동안 const (자연스럽지 않은 소리) 앞에 유형을 넣었고 차이점을 알고 있습니다. 이 기사 는 유용 할 수 있습니다. 그러나 나는이 스타일로 전환 해야하는 이유가 약간 다릅니다.
cnicutar

1
괜찮아. 나는 다른 누군가를 위해 내 자신의 오랜 대답을 썼지 만 당신과 나는이 게시물을 읽고있다. 또한 int const가 나쁜 스타일이고 const int가 좋은 스타일 인 이유를 설명했습니다.
Lundin

Lundin, 나도 읽고 있어요! const int가 더 나은 스타일이라는 데 동의합니다. @cnicutar, Lundin에 대한 첫 번째 답변은이 질문을 제출했을 때 찾고 있던 것입니다. 따라서 문제는 발신자에게 있지 않지만 (무의식적으로 생각한 것처럼) const는 수신자에 대한 보증입니다. 나는이 아이디어를 좋아한다, 고마워
R. Ruiz.

14

에 많이있다 const키워드 것이 있으며 다소 복잡한 키워드입니다. 일반적으로 프로그램에 많은 const를 추가하는 것은 좋은 프로그래밍 관행으로 간주되고 웹에서 "const correctness"를 검색하면 이에 대한 많은 정보를 찾을 수 있습니다.

const 키워드는 소위 "유형 한정자"이고 다른 키워드는 volatileand restrict입니다. 최소한 휘발성은 const와 같은 (혼란스러운) 규칙을 따릅니다.


먼저 const 키워드는 두 가지 목적을 제공합니다. 가장 확실한 방법은 데이터 (및 포인터)를 읽기 전용으로 만들어서 의도적이거나 우발적 인 오용으로부터 보호하는 것입니다. const 변수를 수정하려는 시도는 컴파일 타임에 컴파일러에 의해 발견됩니다.

그러나 읽기 전용 메모리가있는 시스템의 또 다른 목적도 있습니다. 즉, 특정 변수가 이러한 메모리 내에 할당되도록하는 것입니다. 예를 들어 EEPROM이거나 플래시 일 수 있습니다. 이를 비 휘발성 메모리 NVM이라고합니다. NVM에 할당 된 변수는 여전히 const 변수의 모든 규칙을 따릅니다.

const키워드 를 사용하는 방법에는 여러 가지가 있습니다 .

상수 변수를 선언하십시오.

이것은 다음과 같이 수행 할 수 있습니다

const int X=1; or
int const X=1;

이 두 형식은 완전히 같습니다 . 후자의 스타일은 잘못된 스타일로 간주되므로 사용하지 않아야합니다.

두 번째 행이 잘못된 스타일로 간주되는 이유는 아마도 정적 및 extern과 같은 "스토리지 클래스 지정자"도 실제 유형 뒤에 선언 될 수 있기 때문일 수 있습니다 .int static 사용되지 않는 기능으로 표시되는 등 그러나 저장소 클래스 지정자에 대해 이렇게 C위원회에 의해 (ISO 9899 N1539 초안, 6.11.5). 따라서 일관성을 유지하기 위해 형식 한정자를 해당 방식으로 작성해서는 안됩니다. 독자를 혼란스럽게하는 것 외에는 다른 목적이 없습니다.

상수 변수에 대한 포인터를 선언하십시오.

const int* ptr = &X;

이는 'X'의 내용을 수정할 수 없음을 의미합니다. 이것은 "const correctness"에 대한 함수 매개 변수의 일부로 이와 같은 포인터를 선언하는 일반적인 방법입니다. 'X'는 실제로 const로 선언 될 필요가 없으므로 변수 일 수 있습니다. 즉, 변수를 항상 "업그레이드"하여 const로 만들 수 있습니다. 기술적으로 C는 명시 적 타입 캐스트에 의해 const에서 일반 변수로 다운 그레이드 할 수 있지만 그렇게하는 것은 나쁜 프로그래밍으로 간주되며 컴파일러는 일반적으로 경고를합니다.

상수 포인터 선언

int* const ptr = &X;

이것은 포인터 자체 가 일정 하다는 것을 의미합니다 . 가리키는 내용은 수정할 수 있지만 포인터 자체는 수정할 수 없습니다. 이것은 많은 용도가 없으며, 포인터가 가리키는 포인터 (pointer-to-pointer)가 매개 변수로 함수에 전달되는 동안 주소가 변경되지 않도록하는 것과 같은 몇 가지가 있습니다. 다음과 같이 읽을 수없는 것을 작성해야합니다.

void func (int*const* ptrptr)

많은 C 프로그래머가 const와 *를 얻을 수 있을지 의문입니다. 나도 내가 할 수 없습니다 - 나는 GCC 확인했다. 이것이 좋은 프로그래밍 관행으로 간주되지만 포인터 대 포인터의 구문을 거의 보지 못하는 이유입니다.

상수 포인터를 사용하여 포인터 변수 자체가 읽기 전용 메모리에 선언되도록 할 수도 있습니다. 예를 들어 포인터 기반 조회 테이블을 선언하여 NVM에 할당 할 수 있습니다.

물론 다른 답변에서 알 수 있듯이 상수 포인터를 사용하여 "정확도"를 강화할 수도 있습니다.

상수 데이터에 대한 상수 포인터 선언

const int* const ptr=&X;

이것은 위에서 설명한 두 가지 포인터 유형이며 모든 속성이 있습니다.

읽기 전용 멤버 함수 선언 (C ++)

이것은 C ++ 태그가 붙어 있기 때문에 클래스의 멤버 함수를 const로 선언 할 수 있다고 언급해야합니다. 이것은 함수가 호출 될 때 클래스의 다른 멤버를 수정할 수 없다는 것을 의미합니다. 이는 클래스의 프로그래머가 실수로 오류가 발생하는 것을 막을뿐 아니라 멤버 함수의 호출자에게 아무것도 엉망이되지 않음을 알려줍니다 그것을 호출하여. 구문은 다음과 같습니다.

void MyClass::func (void) const;

8

... 오늘 포인터가 함수에 값으로 전달된다는 것을 깨달았습니다.

(imo) 실제로 기본값으로 이해가되지 않습니다. 더 합리적인 기본값은 재 할당 할 수없는 포인터 ( int* const arg) 로 전달하는 것 입니다. 즉, 인수로 전달 된 포인터가 암시 적으로 const로 선언 된 것을 선호했을 것입니다.

const의 장점은 무엇입니까?

장점은 인수가 가리키는 주소를 수정할 때 충분히 쉽고 때로는 명확하지 않다는 것입니다. 따라서 버그가 쉽게 정의되지 않을 때 버그가 발생할 수 있습니다. 주소를 변경하는 것은 비정형입니다. 주소를 수정하려는 경우 로컬 변수를 만드는 것이 더 명확합니다. 또한 원시 포인터 조작은 버그를 쉽게 도입 할 수있는 방법입니다.

따라서 불변 주소로 전달하고 인수가 가리키는 주소를 변경하려고 할 때 (비정상적인 경우) 사본을 만드는 것이 더 명확합니다.

void func(int* const arg) {
    int* a(arg);
    ...
    *a++ = value;
}

로컬을 추가하면 거의 무료이며, 가독성을 높이면서 오류 가능성을 줄입니다.

더 높은 수준에서 : 인수를 배열로 조작하는 경우 일반적으로 클라이언트가 인수를 컨테이너 / 컬렉션으로 선언하는 것이 더 명확하고 오류가 적습니다.

일반적으로 컴파일러가 행복하게 적용하는 부작용을 항상 인식하지는 못하므로 값, 인수 및 주소에 const를 추가하는 것이 좋습니다. 따라서 다른 여러 경우에 사용되는 const만큼 유용합니다 (예 : '왜 const를 값으로 선언해야합니까?'와 같은 질문입니다). 운 좋게도 우리는 또한 재 할당 할 수없는 참조를 가지고 있습니다.


4
이것이 기본값 인 +1. C ++은 대부분의 언어와 마찬가지로 잘못된 방식으로 진행됩니다. const키워드 대신 키워드가 있어야합니다 mutable(잘 알고 있지만 의미가 잘못되었습니다).
Konrad Rudolph

2
const를 기본값으로 사용하는 재미있는 아이디어. 답변 주셔서 감사합니다!
R. Ruiz.

6

메모리에 매핑 된 장치가있는 임베디드 시스템 또는 장치 드라이버 프로그래밍을 수행하는 경우 두 가지 'const'형식이 자주 사용됩니다 (하나는 고정 하드웨어 주소를 가리 키기 때문에). 레지스터가 읽기 전용 하드웨어 레지스터를 가리키면 다른 const가 런타임보다는 컴파일 타임에 많은 오류를 감지합니다.

읽기 전용 16 비트 주변 장치 칩 레지스터는 다음과 같습니다.

static const unsigned short *const peripheral = (unsigned short *)0xfe0000UL;

그러면 어셈블리 언어에 의존하지 않고도 하드웨어 레지스터를 쉽게 읽을 수 있습니다.

input_word = *peripheral;


5

int iVal = 10; int * const ipPtr = & iVal;

일반 const 변수와 마찬가지로 const 포인터는 선언시 값으로 초기화되어야하며 값을 변경할 수 없습니다.

이것은 const 포인터가 항상 같은 값을 가리킴을 의미합니다. 위의 경우 ipPtr은 항상 iVal의 주소를 가리 킵니다. 그러나 가리키는 값이 여전히 상수가 아니기 때문에 포인터 역 참조를 통해 가리키는 값을 변경할 수 있습니다.

* ipPtr = 6; // pnPtr이 비 const int를 가리 키므로 허용


5

포인터뿐만 아니라 다른 유형에 대해서도 동일한 질문을 할 수 있습니다.

/* Why is n const? */
const char *expand(const int n) {
    if (n == 1) return "one";
    if (n == 2) return "two";
    if (n == 3) return "three";
    return "many";
}

LOL, 네 말이 맞아. 포인터가 특별하다고 생각했기 때문에 포인터의 경우가 먼저 떠 올랐지 만 값에 의해 전달되는 다른 변수와 같습니다.
R. Ruiz.

5

귀하의 질문은 실제로 변수를 const 포인터 매개 변수가 아닌 const로 정의하는 이유에 대한 것입니다. 함수 또는 멤버 변수 또는 로컬 변수에 대한 매개 변수 인 경우 변수를 상수로 정의 할 때와 동일한 규칙이 여기에 적용됩니다.

특정 경우에는 기능적으로 로컬 변수를 const로 선언 할 때 다른 많은 경우와 마찬가지로 차이가 없지만이 변수를 수정할 수 없다는 제한이 있습니다.


귀하의 의견은 당신이 옳기 때문에 내 질문이 얼마나 헛된지를 깨닫게합니다 : 그것은 const와 다른 매개 변수를 갖는 것과 같습니다. 쓸모없는 것처럼 보일 수도 있지만 프로그래머가 이러한 제한을 가지고 버그를 피할 수 있도록 도와줍니다
R. Ruiz.

4

const 포인터를 함수에 전달하는 것은 어쨌든 값에 의해 전달되므로 의미가 없습니다. 일반적인 언어 디자인에서 허용되는 것 중 하나 일뿐입니다. 이해가되지 않기 때문에 금지하면 언어 사양이됩니다. 더 큰.

함수 안에 있다면 물론 다른 경우입니다. 가리키는 것을 변경할 수없는 포인터를 갖는 것은 코드를 더 명확하게하는 주장입니다.


4

컴파일러 가이 포인터를 변경할 수 없다는 것을 알고 함수 내에서보다 적극적인 최적화를 수행 할 수 있다는 이점이 있다고 생각합니다.

또한 예를 들어 피한다. 이 포인터를 const가 아닌 포인터 참조를 허용하는 하위 함수에 전달하면 포인터가와 같이 변경 될 수 void f(int *&p)있지만이 경우 유용성이 다소 제한적입니다.


최적화의 경우 +1 적어도 책은 사실이라고 말합니다. 내가 원하는 것은 최적화가 무엇인지 정확히 이해하는 것입니다
R. Ruiz.

4

const 포인터가 적용 가능한 예는 이와 같이 설명 될 수있다. 내부에 동적 배열이있는 클래스가 있고 사용자에게 포인터 변경 권한을 부여하지 않고 배열에 대한 액세스 권한을 전달하려고합니다. 치다:

#include <new>
#include <string.h>

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const GetArray(){ return Array; }
};

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
    Temp.GetArray()[1] = ' '; 
    printf("%s\n",Temp.GetArray());
}

어느 생산 :

입력 데이터
넣기 데이터

그러나 우리가 이것을 시도하면 :

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}

우리는 얻는다 :

오류 : 할당의 왼쪽 피연산자로 lvalue가 필요합니다.

따라서 배열의 내용은 수정할 수 있지만 배열의 포인터는 수정할 수 없습니다. 포인터를 사용자에게 다시 전달할 때 포인터가 일관된 상태를 유지하도록하려면 좋습니다. 그러나 하나의 캐치가 있습니다.

int main()
{
    TestA Temp;
    printf("%s\n",Temp.GetArray());
    Temp.GetArray()[0] = ' ';
    Temp.GetArray()[1] = ' ';
    printf("%s\n",Temp.GetArray());
    delete [] Temp.GetArray(); //Bwuahaha this actually works!
}

포인터 자체를 수정할 수없는 경우에도 포인터의 메모리 참조를 삭제할 수 있습니다.

따라서 메모리 참조가 항상 무언가를 가리 키기를 원한다면 (IE는 절대로 참조가 작동하는 방식과 유사하게 수정되지 않음) 매우 적합합니다. 사용자가 전체 액세스 권한을 갖고 수정하기를 원한다면, 비 const가 당신을위한 것입니다.

편집하다:

GetArray ()가 올바른 값 피연산자로 인해 할당 할 수 없다는 okorz001 의견을 지적한 후에는 주석이 완전히 정확하지만 위의 내용은 포인터에 대한 참조를 반환하는 경우에도 여전히 적용됩니다 (GetArray가 예를 들어 참조를 참조하십시오.

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; } //Note & reference operator
        char * &GetNonConstArray(){ return Array; } //Note non-const
};

int main()
{
    TestA Temp;
    Temp.GetArray() = NULL; //Returns error
    Temp.GetNonConstArray() = NULL; //Returns no error
}

첫 번째 오류를 반환합니다 :

오류 : 읽기 전용 위치 'Temp.TestA :: GetArray ()'할당

그러나 두 번째는 아래에 잠재적 결과에도 불구하고 즐겁게 발생합니다.

분명히 '왜 포인터에 대한 참조를 반환하고 싶습니까?'라는 질문이 제기 될 것입니다. 문제의 원래 포인터에 직접 메모리 (또는 데이터)를 할당해야하는 경우가 드물지만 (예 : 자신의 malloc / free 또는 new / free 프론트 엔드 구축),이 경우에는 상수가 아닌 참조입니다 . const 포인터에 대한 참조 나는 그것을 반환하는 상황을 보지 못했습니다 (반환 유형이 아닌 선언 된 const 참조 변수가 아닌 한)?

const 포인터를 사용하는 함수가 없는지 고려하십시오 (그렇지 않은 함수 포인터).

class TestA
{
    private:
        char *Array;
    public:
        TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
        ~TestA(){if(Array != NULL){ delete [] Array;} }

        char * const &GetArray(){ return Array; }

        void ModifyArrayConst(char * const Data)
        {
            Data[1]; //This is okay, this refers to Data[1]
            Data--; //Produces an error. Don't want to Decrement that.
            printf("Const: %c\n",Data[1]);
        }

        void ModifyArrayNonConst(char * Data)
        {
            Data--; //Argh noo what are you doing?!
            Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
            printf("NonConst: %c\n",Data[1]);
        }
};

int main()
{
    TestA Temp;
    Temp.ModifyArrayNonConst("ABCD");
    Temp.ModifyArrayConst("ABCD");
}

const의 오류는 다음과 같은 메시지를 생성합니다.

오류 : 읽기 전용 매개 변수 'Data'감소

주석에 표시된 문제를 일으키고 싶지 않다면 그렇게하고 싶지 않은 것이 좋습니다. const 함수에서 감소를 편집하면 다음이 발생합니다.


Const : A Const : B

분명히 A가 'Data [1]'이더라도 NonConst 포인터가 감소 연산을 허용했기 때문에 'Data [0]'으로 취급됩니다. const를 구현하면 다른 사람이 쓸 때 잠재적 버그가 발생하기 전에 잡을 수 있습니다.

또 다른 주요 고려 사항은 참조가 가리키는 것을 변경할 수 없다는 점에서 const 포인터를 의사 참조로 사용할 수 있다는 것입니다 (이것이 어떻게 구현되었는지 궁금 할 것입니다). 치다:

int main()
{
    int A = 10;
    int * const B = &A;
    *B = 20; //This is permitted
    printf("%d\n",A);
    B = NULL; //This produces an error
}

컴파일을 시도하면 다음 오류가 발생합니다.

오류 : 읽기 전용 변수 'B'할당

A에 대한 지속적인 참조를 원한다면 아마도 나쁜 것입니다. B = NULL주석 처리 된 경우 컴파일러는 행복하게 수정할 수 *B있으므로 A를 사용할 수 있습니다. 이것은 int에서는 유용하지 않을 수 있지만 통과 할 수있는 참조 할 수없는 포인터를 원하는 그래픽 응용 프로그램의 단일 자세가 있는지 고려하십시오. 주위에.

사용법은 가변적이지만 (의도하지 않은 말장난을 제외하고) 올바르게 사용하면 프로그래밍을 지원하는 상자의 또 다른 도구입니다.


2
Temp.GetArray() = NULLTemp.GetArray()const 한정이기 때문에 가 아니라 rvalue 이기 때문에 실패합니다 . 또한 const 한정자가 모든 반환 유형에서 제거되었다고 생각합니다.
Oscar Korz

@ okorz001 : 테스트 후, 당신은 실제로 맞습니다. 그러나 포인터 자체에 대한 참조를 반환하면 위의 내용이 적용됩니다. 그에 따라 게시물을 편집하겠습니다.
SSight3

3

포인터가 const가되기를 원하지 않는 포인터에는 특별한 것이 없습니다. 클래스 멤버 상수 int값을 가질 수있는 것과 마찬가지로 유사한 이유로 상수 포인터를 가질 수도 있습니다. 가리키고있는 것을 변경하는 사람이 없도록하십시오. C ++ 참조는이 문제를 다소 해결하지만 포인터 동작은 C에서 상속됩니다.



3


(1) 상수 변수 선언과 같은 변수 선언 유형
DataType const varibleName;

 int const x;
    x=4; //you can assign its value only One time
(2) 상수 변수에 대한 포인터를 선언하십시오.
const dataType* PointerVaribleName=&X;
 const int* ptr = &X;
     //Here pointer variable refer contents of 'X' that is const Such that its cannot be modified
dataType* const PointerVaribleName=&X;
 int* const ptr = &X;
     //Here pointer variable itself is constant  Such that value of 'X'  can be modified But pointer can't be modified


우리는 실제 값을 바꾸고 싶지 않을 때 인수로 함수에 const로 포인터 변수를 제공합니다
Pyadav
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.