C++/탐구

Reference

WhNi 2024. 3. 20. 11:17

&은 생각보다 많이 쓰이고 중요한 개념이지만 역할이 많아서 인지 헷갈리는 경우가 많다.

 

대부분 원본 데이터를 직접 건드린다는 점에서 기억에 남지만 

 

이번 기회에 확실하게 개념을 짚고 가야겠다.

 

간단한 예시를 보자

#include <iostream>
using namespace std;

int main()
{
	int x = 10;
	int& y = x;
	cout << y << "\n";
	//y 에 x 값이 대입되었다.
    //  y = 10

	y = 20;
	cout << x << "\n";
	// y가 바뀌었지만 x의 값도 바뀌었다.
    // x= 20;

	x = 30;
	cout << y << "\n";
	// x 값을 바꿔도 y가 같이 바뀐다. 
    // y= 30;
}

 

다음은 매개변수에서 &가 붙었을 때이다.

#include <iostream>

using namespace std;

void swap(int& a, int& b)
// 함수의 매개변수에 붙은 &는 전달된 변수의 값을 직접 수정할 수 있다. 
// 즉 함수 내부에서 변경된 값들이 실제 외부 변수에도 영향을 미친다.
// &가 없다면 이 스택 내부에서 일어난 변경은 외부변수가 변경되지 않는다.
// &가 없다면 결과는 2,3 그대로
{
	int temp = a;
	a = b;
	b = temp;
}

int main()
{
	int a = 2, b = 3;

	swap(a, b);
// 결과는 a = 3, b = 2;
}

 

다음은 구조체 혹은 클래스에서 &가 사용되는 경우이다.

#include <iostream>

using namespace std;

struct Student
{
	Student(string _name, string _adress, int _rollNo)
	{
		name = _name;
		adress = _adress;
		rollNo = _rollNo;
	}
	string name;
	string adress;
	int rollNo;
};

void print(Student& s)
{
	s.name = "Olive";
	cout << s.name << " " << s.adress << " " << s.rollNo << "\n";
}

int main()
{
	Student A("Kevin", "Seoul", 1);
	print(A);
    // print 함수에서 이름을 변경했으면, 원본에도 영향을 미쳐서 A.name = Olive 이다.
    // print(const Student& s) 라고 하면 (읽기 전용) 함수 내에서 변경이 불가해짐( 컴파일러에서 에러)
    // 이렇게 된다면 A.name은 Kevin
    // print(Student s) 라고 하면 복사된 s가 Olive가 되고,
    // 원본 A는 그대로 Kevin일 것이다.
	cout << A.name << "\n";
}

이부분은 Call by Value와 Call by Reference인 부분이다.

 

 

다음은 for문으로 구성했을때 &가 사용되는 경우이다.

#include <iostream>
#include <vector>

using namespace std;


int main()
{
	vector<int> h ={ 10,20,30,40 };

	for (int& x : h)
	{
		x += 5;
	}

	for (int x : h)
	{
		cout << x << "\n";
	}
    // 만약 순서가 바뀐다면, 결과는 10,20,30,40 이다.
    
   	vector<string> v = { "practice", "write","idea" };

	for (const string& x : v)
	{
		cout << x << "\n";
	}
}

 

마지막으로 포인터와 참조변수의 차이이다.

#include <iostream>

using namespace std;

int main()
{
	int i = 10;

	int* p = &i;
	cout << p << "\n";

	int** pr = &p;
	cout << pr << "\n";

	int*** ptr = &pr;
	cout << ptr << "\n""\n";
    // 결과는 각자 다른 주소값을 출력한다.

	int a = 5;
	int& S = a;
	cout << &S << "\n";

	int& S0 = S;
	cout << &S0 << "\n";

	int& S1 = S0;
	cout << &S1 << "\n";
    // 결과는 같은 주소값을 출력한다. 
}

포인터는 새로운 주소가 배정되는 반면, 참조는 같은 주소값을 출력한다. 그래서 포인터의 경우는 중간에 값을 바꾸면 중간값부터 그 값이 바뀌게되지만, 참조의 경우는 중간에 바꾸면 전체 값이 바뀌게 된다.

 

정리하자면, 매개변수로 있을때는 직접 변수의 영향을 주는것이고, 해당 데이터를 읽기만 한다면 const를 붙여서 읽기 전용으로 읽어드리는게 좋다. 없다면 copy 본이 만들어지니까 CPU 차지도 하게되고 악영향을 끼치게 된다.

 

const와 Reference를 잘 쓰는게 리소스 낭비를 하지 않는 중요한 개념중 하나이니까 잘 챙기도록 하자.