(수정중) [C++] string 그리고 &
2025. 8. 9. 08:54
std::string을 레퍼런스(reference) 타입으로 전달하면 주로 다음과 같은 장점이 있습니다.
---
1. 불필요한 복사 비용 절감
void funcByValue(std::string s) { } // 값 전달
void funcByRef(const std::string& s) { } // 참조 전달
값 전달: 매개변수 s를 만들기 위해 원본 문자열을 복사해야 함.
→ 문자열이 클수록 복사 비용(메모리 할당 + 데이터 복사)이 커짐.
참조 전달: 원본 데이터를 그대로 참조하므로 복사 없음.
→ 포인터 하나 넘기는 수준의 가벼운 연산.
📌 예:
#include <iostream>
#include <string>
#include <chrono>
using namespace std;
using namespace chrono;
void byValue(string s) { }
void byRef(const string& s) { }
int main() {
string big(1000000, 'A'); // 100만 글자짜리 문자열
auto t1 = high_resolution_clock::now();
byValue(big);
auto t2 = high_resolution_clock::now();
auto t3 = high_resolution_clock::now();
byRef(big);
auto t4 = high_resolution_clock::now();
cout << "byValue: " << duration_cast<microseconds>(t2-t1).count() << "us\n";
cout << "byRef : " << duration_cast<microseconds>(t4-t3).count() << "us\n";
}
byValue는 큰 문자열 복사 때문에 시간이 오래 걸리고, byRef는 훨씬 빠름.
---
2. 원본 수정 가능 여부 선택
string& → 참조로 받고 원본 수정 가능
const string& → 참조로 받지만 수정 불가
void modify(string& s) { s += "!!!"; }
void readOnly(const string& s) { cout << s; }
원본 수정이 필요 없으면 const string&가 안전하고 일반적.
---
3. 일관된 인터페이스
문자열을 함수에 넘길 때, 값/레퍼런스를 섞어 쓰면 함수 동작 방식이 달라질 수 있음.
큰 객체는 대부분 const &로 받는 게 표준적인 습관.
---
4. 불필요한 메모리 할당 방지
복사 초기화 시 힙 메모리 할당이 일어나는데, 참조 전달은 이런 힙 할당 자체가 없음.
특히 루프에서 함수가 자주 호출되는 경우 차이가 큼.
---
요약
전달 방식 장점 단점
값(string s) 독립 복사본 → 함수 내에서 자유롭게 변경 가능, 원본 영향 없음 큰 문자열이면 복사 비용 큼
참조(string&) 복사 없음, 원본 수정 가능 원본이 의도치 않게 변경될 위험
const string& 복사 없음, 안전하게 읽기 전용 함수 내에서 수정 불가
---
제가 보기엔
읽기 전용이면 무조건 const string&
수정이 필요하면 string&
값 전달은 작은 문자열이거나 수정 후 원본 보존이 필요할 때만
이게 제일 실무적인 가이드입니다.
---
원하시면 제가 값 전달 vs const 참조 전달의 메모리 구조 차이를 그림으로도 보여드릴 수 있습니다.
그러면 "복사 없음"이 어떤 의미인지 확실히 보입니다.
C++에서 std::string을 함수에 매개변수로 전달할 때, 값(by value)이 아닌 레퍼런스(by reference) 타입으로 전달하면 여러 가지 장점이 있습니다. 주요 장점들을 아래에 정리했습니다.
1. 성능 (Performance)
값 전달 (Pass by Value):
* std::string 객체 전체가 복사됩니다.
* std::string은 내부적으로 문자열 데이터를 동적 할당하기 때문에, 복사 시 새로운 메모리를 할당하고 기존 문자열을 새로운 메모리에 복사하는 비용이 발생합니다.
* 문자열의 길이가 길수록 복사 비용은 기하급수적으로 증가합니다.
레퍼런스 전달 (Pass by Reference):
* std::string 객체 자체가 아닌, 객체의 메모리 주소(레퍼런스)만 전달합니다.
* 따라서 std::string 객체의 복사 비용이 발생하지 않습니다.
* 함수 내부에서 원본 객체를 직접 접근하고 수정하므로, 매우 빠르고 효율적입니다.
* 이는 특히 함수가 자주 호출되거나, 전달되는 문자열의 크기가 클 때 성능 차이가 크게 나타납니다.
2. 코드 가독성 및 의도 명확화
* const 레퍼런스 사용: const std::string&와 같이 const 키워드를 함께 사용하면, 함수 내부에서 전달된 문자열을 수정하지 않겠다는 의도를 명확하게 보여줄 수 있습니다.
* 이는 컴파일러에게도 최적화 힌트를 제공하며, 코드를 읽는 다른 개발자에게도 함수가 단지 문자열의 내용을 읽기만 한다는 것을 알려줍니다.
* 또한, const 레퍼런스를 사용함으로써 실수로 원본 문자열을 변경하는 것을 방지할 수 있습니다.
3. 유연성 및 편리성
* 레퍼런스 전달은 함수가 인수로 전달된 객체를 직접 수정해야 할 때 필수적입니다.
* 예를 들어, 문자열을 변형하여 반환하는 함수를 만들 때, 새로운 문자열을 반환하는 대신 레퍼런스를 통해 원본 문자열을 직접 수정함으로써 메모리 할당과 복사 비용을 줄일 수 있습니다.
예시:
아래 두 함수의 성능 차이를 비교해 봅시다.
값 전달 (비효율적):
#include <iostream>
#include <string>
void print_string_by_value(std::string str) {
// str은 원본 문자열의 복사본입니다.
// 함수 호출 시 복사 비용이 발생합니다.
std::cout << str << std::endl;
}
int main() {
std::string my_string = "This is a very long string that will be copied.";
print_string_by_value(my_string); // my_string이 복사됨
return 0;
}
레퍼런스 전달 (효율적이고 권장됨):
#include <iostream>
#include <string>
// const 레퍼런스: 원본을 수정하지 않고 읽기만 할 때 사용
void print_string_by_const_reference(const std::string& str) {
// str은 원본의 별칭(alias)입니다.
// 복사 비용이 발생하지 않습니다.
std::cout << str << std::endl;
}
// 일반 레퍼런스: 원본을 수정해야 할 때 사용
void append_string_by_reference(std::string& str) {
str += " - appended.";
}
int main() {
std::string my_string = "Hello, World";
// 원본을 복사하지 않고 함수에 전달
print_string_by_const_reference(my_string);
// 원본을 수정
append_string_by_reference(my_string);
std::cout << "After modification: " << my_string << std::endl; // 출력: Hello, World - appended.
return 0;
}
결론
대부분의 경우, std::string을 함수에 전달할 때는 **const 레퍼런스 (const std::string&)**를 사용하는 것이 가장 좋은 방법입니다.
* 읽기 전용으로 사용할 때: const std::string&를 사용하면 성능 향상과 더불어 코드의 의도를 명확하게 전달할 수 있습니다.
* 수정이 필요할 때: std::string&를 사용하여 원본 객체를 직접 수정할 수 있습니다.
* 값 전달은 함수 내부에서 객체의 독립적인 복사본이 필요할 때만 사용해야 합니다. (예: std::string이 함수 내부에서 반드시 수정되어야 하고, 그 결과가 외부로 전달되지 않을 때)
따라서 레퍼런스 타입으로 전달하는 것은 C++에서 리소스를 효율적으로 사용하고, 안전하며, 가독성이 높은 코드를 작성하는 데 있어 매우 중요한 모범 사례입니다.
'C++ > C++' 카테고리의 다른 글
| [C++] unordered_map (0) | 2025.12.22 |
|---|---|
| [C++] string 초기화 및 생성자 (1) | 2025.08.09 |
| [C/C++] SIGSEGV, SIGABRT 등 시그널(Signal) 에러에 관한 고찰 (0) | 2025.06.04 |
| [C/C++] Signal(시그널) 종류 및 설명 (0) | 2025.06.04 |
| [C++] 가변인자를 다른 함수로 바로(by pass) 전달하는 방법 (0) | 2025.05.09 |
