내 세상

[C++] 동적 메모리/ 레퍼런스 본문

Language/C/C++

[C++] 동적 메모리/ 레퍼런스

sga8 2020. 1. 2. 20:03
728x90
반응형

C++의 new, delete 사용 예시

#include <iostream>

int main()
{
	// C스타일 메모리 할당
	// C   : void* => int* 로 암시적 변환 가능
	// C++ : void* => int* 로 암시적 변환 불가능
	int *p1 = static_cast<int*>(malloc(100)); // sizeof(int)*10

	free(p1);

	// C++ 스타일
	int *p2 = new int;
	delete p2;

	int* p2 = new int[10]; // 배열 버전, sizeof(int)*10;
	delete[] p2; // 해지 할때도 배열 버전의 delete 사용

	int* p3 = new int[10];
	delete p3; // 이렇게 한다면?
					// 표준 문서에서 어떻게 될거 라고 정의 한적이 없다.
					// 사용하지 말아야 한다.
					// "undefined(미정의 동작)"이라고 한다.

	// malloc : 함수  , 크기전달, void* 반환    , 생성자 호출 안됨
	// new    : 연산자, 타입전달, 정확한 타입반환, 생성자 호출 됨
}

 

&(reference) 활용 예시

#include <iostream>

int main()
{
	int n1 = 10;
	int n2 = n1;

	int* p1 = &n1;

	int& r1 = n1; // 기존 메모리의 별칭(alias)


	std::cout << &n1 << std::endl;
	std::cout << &r1 << std::endl;

	r1 = 100; // 결국 n1에 넣게 됩니다.
	std::cout << n1 << std::endl;

	// 주의사항
	int* p2; // ok.. 초기화되지 않은 포인터 변수는 생성 가능
	int& r2; // error. 레퍼런스 변수는 반드시 초기화가 필요하다.
					// 기존 메모리를 가르키는 것이기 때문에.
}

 

call by value, call by pointer, call by reference

#include <iostream>

void inc1(int  n) { ++n; }
void inc2(int* p) { ++(*p); }
void inc3(int& r) { 
	int* p = 0;
	int& r2 = *p; // 레퍼런스도 null이 될 수 있다!! 최악의 코드

	// 하지만 일반적인 경우에는 null reference는 체크 할 필요는 없다.
	++r; 

	// 레퍼런스 : 안전하고 사용하기 쉬운 포인터라고도 합니다.
	//		     "자동 deferencing 되는 포인터!!"
}

int main()
{
	int a = 1, b = 1, c = 1;
	inc1(a); // call by value.. 복사본 생성, 증가 안됨.

	// 레퍼런스 : 포인터와 유사하게 함수인자로 메모리 정보를
	//			  보내고 싶을 때 사용

	inc2(&b); // call by pointer.. 메모리 정보(주소) 전달, 증가됨.
			  // 포인터 변수는 대부분 사용시 null을 확인하는 것이 안전하다.
			  // 하지만 일반적인 경우에는 null reference는 체크할 필요는 없다.
					// inc2(int* p) { if(p==0){} ++(*p); }
	int3(c); // call by reference. 메모리에 대한 또 다른 이름 제공, 증가됨.

	std::cout << a << std::endl;
	std::cout << b << std::endl;
	std::cout << c << std::endl;
}

 

const & 의 사용

#include <iostream>

struct BigData {
	int data[10];
};

// call by value : 원본을 수정하지 않겠다는 약속
// void foo(int a)
//void foo(BigData a) 
void foo(const BigData& a)
{
	a = 10; // 원본을 수정하려고 하면 에러

	// 결론 : call by value보다 const & 가 좋다 !!!!
}
int main()
{
	//int x = 10;
	BigData x;
	foo(x); // foo 안에서는 절대 x의 값을 변경하면 안된다.

	std::cout << x << std::endl; // 반드시 10 나와야 한다.
}


// 인자 값을 변경하지 않는 함수 입니다. 좋은 코드는 ?
void foo(int a) {}  // 1
void foo(const int& a) {} // 2

// 함수 인자 가이드라인

// 1. 인자 값을 변경하지 않는 함수
//       A. primitive type : call by value      foo(int n)
//       B. user define type : const reference  foo(const Data& d)
//
// 2. 인자 값을 변경해야 한다면
//       A. 포인터도 나쁘지 않고     foo(int* p)
//       B. 레퍼런스도 나쁘지 않다.  foo(int& r)

//       예전에는 A를 선호(가독성 측면), 요즘은 B를 선호(안전성 측면)
728x90
반응형

'Language > C/C++' 카테고리의 다른 글

[C/C++] const VS #define  (0) 2021.02.16
[C++] nullptr  (0) 2020.01.02
[C++] C++스타일의 캐스팅  (0) 2020.01.02
[C++] C++11/C++17 에서의 반복문/제어문  (0) 2020.01.02
[C++] 함수  (0) 2020.01.02