프로그래밍을 하다 보면 함수의 인자에 std::vector 등의 STL 데이터 타입을 넣는 경우가 있다.
이때 메모리 문제나 속도 문제에 대해서 생각해 필요가 있다.
값에 의한 호출 call by value
void func1(std::vector v) {...}
int main(){
std::vector my_v {0,0,0};
func1(my_v);
}
이 경우 v는 main()의 my_v를 넘기는 순간에 값을 복사하기 때문에 메모리가 증가하게 된다.
func1에서 v를 수정할 경우 main()의 my_v에 영향을 줄 수 없다.
만약에 main()에서 fun1()를 여러번 호출하게 된다면 매번 메모리가 사용될 것이다. 벡터는 상당히 큰 메모리 공간을 가질 수 있으므로 함수에 전달할 때 신중하게 고려해야 한다.
void func1(std::vector v) {...}
int main(){
std::vector my_v {0,0,0};
for(1~n){ func1(my_v); }
}
참조에 의한 호출 call by reference
void func2(std::vector& v) {...}
void func3(std::vector const& v) {...}
int main(){
std::vector my_v {0,0,0};
func2(my_v);
func3(my_v);
}
main함수에서 func2()는 my_v를 넘기는 순간에 복사가 일어난다. 다만 복사되는 값이 my_v의 주소 값이다.
주소 값을 넘겼으므로 함수 func2()는 main()의 my_v에 영향을 줄 수 있다.
함수 func3()는 const 한정자를 사용하므로 읽기 전용이 된다.
함수에서 STL 데이터 받기
std::vector func4(){
std::vector v {0,0,0};
return v;
}
std::vector& func5(std::vector& v){
return v;
}
int main(){
std::vector my_v1 = func4();
std::vector my_v2 = func5(my_v1); //my_v1과 my_v2는 별개의 변수
std::vector& my_v3 = func5(my_v1);//참조자로 받았으므로 my_v1과 my_v3은 같음
}
my_v2는 일반 변수로 참조자를 반환받고 있어서 my_v1과 별개의 변수가 된다.
my_v3는 참조자로 참조자를 반환 받고 있어서 my_v1과 같은 메모리 위치에 있다.
my_v1는 v가 제대로 복사된다.
아래 코드와 같은 형태로 컴파일러가 데이터를 call by reference를 하여 func4()의 v 값들이 my_v1에 이동한다.
void func4(std::vector& v){
v.push_back(0);
v.push_back(0);
v.push_back(0);
}
int main(){
std::vector my_v1;
func4(my_v1);
}
함수에서 참조자를 반환할 때 주의해야 할 점이 있다. 코드를 살펴보면
std::vector& func(){
std::vector v={1,2,3};
return v;
}
int main(){
vector<int>& my_v = func();
}
func() 함수는 반환형이 참조자인데 지역 변수를 반환하고 있다. my_v는 지역변수은 v를 참조하고 싶은데 func() 함수가 끝나면서 메모리에서 지역변수 v가 소멸될 것이고 참조하지 못한 my_v는 오류가 날 것이다.
(v를 반환하는 부분에서 컴파일 경고가 발생한다.)
이렇게 해제된 메모리를 참조하는 참조자를 댕글링 레퍼런스(Dangling Reference)라고 한다.
'C++ > 문법' 카테고리의 다른 글
c++ regex 정규 표현식 (0) | 2021.12.22 |
---|---|
if문 속 비교연산에서 순서의 비밀 (0) | 2021.08.30 |
C++) Container비교 (0) | 2021.08.25 |
C++) cout 스트림 버퍼/ 함수 호출 오버헤드/ Inline함수 (0) | 2021.05.08 |