ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 참조자의 내부 동작
    C++ 언어 2020. 3. 27. 14:09
    // HelloNew_C+.cpp : 콘솔 응용 프로그램에 대한 진입점을 정의합니다.
    //
    
    #include "stdafx.h"
    #include<iostream>
    #include<cstdio>
    #include<string>
    
    // 참조자의 내부 구조
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	int a(10), b(20);
    	// 포인터의 구조적 문제는 포인터가 가리키는 값 즉 주소가
    	// 변질 될 수 있다. 
    
    	// 포인터 변수 사용
    	int* pn_data = &a;
    
    	// pn_data는 변수이기 때문에 값이 변경 가능
    	pn_data = &b;
    
    	// pn_data의 자료형은 int * 이기 때문에 해당 주소가 가리키는 메모리의 값 역시 변경 가능
    	*pn_data = 50;
    
    	// 위와 같이 pn_data는 변수이기 때문에 &a를 가리키다 &b를 가리킬 수도 있다 즉 값이 변질 될 수 있음
    	// 따라서 pn_data 자체를 상수화 시킴으로서 포인터 변수의 본질적 문제를 막을 수 있음
    
    	// 포인터 상수 사용
    	int* const pn_data = &a; // 포인터 변수 -> 포인터 상수
    
    	// pn_data가 변수에서 상수로 변화함에 따라 pn_data의 값은 변경할수 없게 된다.
    	pn_data = &b; // Error
    	// 하지만 pn_data 포인터 상수가 가리키는 값 즉 간접지정한 값은 변경할 수 있다.
    	*pn_data = 10;
    
    
    
    	return 0;
    }
    
    

    위와 같이 포인터를 사용할 경우 포인터가 가리키는 값 즉 포인터 안에 있는 주소가 변경 (Over Write) 될 수가 있다. 예를 들어 개발자의 실수로 포인터의 값을 실수로 다른 메모리의 주소로 변경 할 경우 다른 메모리에 다른 값이 Over Write 된다 따라서 기존에 있던 값이 지워지며 새로운 값이 써져 버리는 것이다. C 언어가 제공하는 포인터의 자유성으로 인해 위와 같은 문제가 발생 할 수 있다.

    따라서 포인터를 변수로써 사용하는 것이 아니라 const를 사용해 상수형태로 사용하면 위와 같이 포인터가 가리키는 값 즉 주소가 상수화 됨에 따라 사용자의 실수로 인해 주소가 변질 되는 문제는 막을 수 있다.

    EX ) 

    int* pn_data = &a   =>   pn_data = & b 

    위의 코드는 가능 포인터가 변수형태 이기 때문에 새로운 값인 &b 로 변경 될 수 있음

    int* const pn_data = &a    =>   pn_data = &b  

    위의 코드는 불가능 포인터가 상수화 됨에따라 안에 있는 &a 라는 값을 변경 할 수 없다.

     

    이제 위와 같이 const 를 이용해 포인터 변수를 상수화 시켜 포인터가 다른 주소를 가리키게 되는 문제를 방지할 수 있다. 이때 const 와 같이 사용자가 직접 상수화 시키지 않고 애초에 상수 형태의 포인터를 제공해주는 문법을 C++ 에서 제공하는데 이것이 바로 참조자인 것이다. 

    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	int a = 1;
    	int *pn_data = &a;
    	int b = 2;
    	int c = 3;
    	
    
    	*pn_data = 3;
    
    	return 0;
    }

    위의 코드를 보면 Stack Frame 구조에 따라 메모리의 아래부터 위쪽으로 차례대로 쌓이면서 Data 가 저장 될 것이다.

    위의 자료를 보면 Stack 메모리의 구조적 특성 대로 아래에서 위로 차례 대로 메모리가 할당 되는 것을 볼 수 있으며, 이때 0x00A9FCE8 이라는 메모리의 주소에 위치한 것이 pn_data 변수이다. 따라서 pn_data 포인터 변수에 담긴 값은 a 메모리의 값은 0x00A9FCF4 이다. 여기 까지는 포인터의 당연한 결과이다. 그렇다면 참조자는 어떻게 동작하는지 살펴보자

    위와 같이 아래에서 위로 차례대로 메모리가 할당 되며 데이터가 들어간다. 이때 중요하게 볼 부분은 다음과 같다.

    &pn_data = a ; 즉 참조자 pn_data를 선언하고 해당 참조자의 참조 값을 a 메모리로 초기화 하는 구문에서 위와 같이 0x005EF9B4 의 메모리 값으로 a 변수의 주소가 들어간다.

    따라서 참조자는 내부적으로 포인터와 동일하게 동작하고 있으며 이때 포인터의 변수의 본질적 문제인 값이 Over Write 되는 현상을 막기 위해 0x005EF9B4의 메모리를 변수로 사용하는 것이 아닌 0x005EF9B4 메모리를 상수 형태로 사용하여 0x005EF9B4 메모리 안의 값이 변경되지 않게 한다.

    int* const pn_data = &a ;

    int &pn_data = a ;

    즉 위와 같이 포인터 변수를 상수화 시켜 해당 값이 변경되는 것을 막는 것을 C++ 에서는 참조자라는 개념으로 사용하는 것이다.

    'C++ 언어' 카테고리의 다른 글

    Class의 생성 과정  (0) 2020.03.31
    함수 템플릿과 인라인 함수  (0) 2020.03.30
    참조형과 포인터  (0) 2020.03.26
    C++ 메모리 동적할당 및 해제 ( new & delete )  (0) 2020.03.26
    C++ 의 변수 선언  (0) 2020.03.26

    댓글

Designed by Tistory.