인사
안녕하세요. 오늘은 C++ 언어를 공부하면서 새롭게 알게 된 모듈과 함수에 대해 정리해 보려 합니다. 이번 포스팅에서 다룰 주제는 바로 std::array와 std::vector의 조합입니다.
문제의 시작
아래는 제가 처음 시도했던 코드입니다. vector 안에 int[MAX_N] 형태의 배열을 넣으려 했습니다:
#include <stdio.h>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#define MAX_N 100
void InputVector(int n, std::vector<int [MAX_N]>& v) {
int i;
for (i = 0; i < n; i++) {
// input
std::string s;
getline(std::cin, s);
std::istringstream iss(s);
int value, j = 0;
int arr [MAX_N];
while (iss >> value) {
arr[j++] = value;
}
v.push_back(arr);
}
}
void Answer(int n, std::vector<int [MAX_N]>& v) {
for (auto a : v) {
int answer = 0;
for (int i = 0; i < n; i++) {
answer += a[i];
}
printf("%d\n", answer);
}
}
int main(void) {
// n
int n;
scanf("%d", &n);
getchar();
// vector
std::vector<int [MAX_N]> v;
v.reserve(n);
InputVector(n, v);
// answer
Answer(n, v);
return 0;
}
하지만 컴파일 에러가 발생했습니다. 이유를 조사해보니 vector는 내부적으로 타입 T의 복사 생성자와 대입 연산자가 필요하다는 것을 알게 되었습니다. 그런데 C++의 기본 배열 타입(int[])은 이러한 기능을 제공하지 않기 때문에 문제가 생겼던 것입니다.
또한, 배열은 포인터로 해석되기 때문에 같은 배열처럼 보여도 실제로는 복사가 아닌 주소 참조가 일어납니다. 이로 인해 vector에 push할 때 모든 요소가 동일한 배열을 참조하는 심각한 오류가 발생하게 됩니다.
#include <stdio.h>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
void InputVector(int n, std::vector<std::string>& v) {
int i;
for (i = 0; i < n; i++) {
std::string s;
getline(std::cin, s);
v.push_back(s);
}
}
void Answer(std::vector<std::string>& v) {
for (auto a : v) {
std::istringstream iss(a);
int value, answer = 0;
while (iss >> value) {
answer += value;
}
printf("%d\n", answer);
}
}
int main(void) {
// n
int n;
scanf("%d", &n);
getchar();
// vector
std::vector<std::string> v;
InputVector(n, v);
// answer
Answer(v);
return 0;
}
사실 이렇게 짜는게 가장 효율적인것 같긴 합니다...
해결책
보다 근본적인 해결책은 C++의 std::array를 사용하는 것이었습니다. std::array<int, MAX_N>는 고정 크기의 배열처럼 작동하지만 STL 컨테이너의 특징도 가지고 있어서, vector와 함께 사용할 수 있습니다.
아래는 개선된 코드입니다:
#include <stdio.h>
#include <vector>
#include <array>
#include <string>
#include <iostream>
#include <sstream>
#define MAX_N 100
void InputVector(int n, std::vector<std::array<int, MAX_N>>& v, std::array<int, MAX_N>& arr ,int* cnt) {
int i;
for (i = 0; i < n; i++) {
cnt[i] = 0;
}
for (i = 0; i < n; i++) {
std::string s;
getline(std::cin, s);
std::istringstream iss(s);
int value;
while (iss >> value) {
arr[cnt[i]] = value;
cnt[i] += 1;
}
v.push_back(arr);
}
}
void Answer(int* cnt, std::vector<std::array<int, MAX_N>>& v) {
int i = 0;
for (auto a : v) {
int n = cnt[i++];
int j, answer = 0;
for (j = 0; j < n; j++) {
answer += a[j];
}
printf("%d\n", answer);
}
}
int main(void) {
// n
int n;
scanf("%d", &n);
getchar();
// vector
std::vector<std::array<int, MAX_N>> v;
std::array<int, MAX_N> arr;
int* cnt = new int [n];
InputVector(n, v, arr, cnt);
// answer
Answer(cnt, v);
// delete
delete[] cnt;
return 0;
}
이렇게 하면 배열을 안전하게 복사하고 저장할 수 있고, vector의 장점도 그대로 활용할 수 있습니다. 또한 std::array는 new로 할당한 배열과 달리 명시적인 delete[] 처리가 필요 없어 메모리 관리가 한결 간단합니다.
그렇다면 항상 std::array를 사용하는 것이 정답일까요? 이에 대한 궁금증을 해결하기 위해 두 방식의 장단점을 비교해 보았습니다.
일반적으로 new int[]를 사용하면 런타임에 크기를 유동적으로 지정할 수 있고, 상대적으로 더 많은 데이터를 다룰 수 있다는 장점이 있습니다. 반면 std::array는 정해진 크기의 배열이지만 복사와 대입이 안전하게 이루어지고, STL 컨테이너들과의 호환성도 뛰어납니다.
결국 중요한 건 상황에 맞는 선택입니다. 메모리 크기나 유연성이 중요한 경우엔 new 방식이 유리하고, 안정성과 관리 편의성을 중시한다면 std::array가 더 적합할 수 있습니다.
필요에 따라 가장 적절한 도구를 선택하는 것이 중요한 포인트였습니다.
마무리
오늘은 vector에 배열을 넣으려다 생긴 문제와 이를 std::array로 해결하는 과정을 정리해보았습니다. 단순히 동작하는 코드가 아닌, C++ 언어의 특성과 컨테이너 사용법에 대해 한층 깊이 이해할 수 있는 계기가 되었습니다.
앞으로도 공부하면서 얻은 인사이트나 실수, 해결 방법들을 기록해 나가려 합니다. 이 글이 같은 고민을 가진 분들께 도움이 되길 바라며, 여러분의 개발도 항상 좋은 방향으로 나아가길 응원합니다.
화이팅입니다.