동적 배열과 vector

박재민·2022년 4월 21일
0
post-thumbnail

이번 포스팅에서는 동적 배열과 C++ vector에 대해 정리해 보려고 합니다.


동적 배열

동적 배열이란 동적 메모리 할당을 이용해 생성한 배열을 말합니다.

동적 메모리 할당(Dynamic memory allocation)이란?

프로그램 실행 중 필요한 크기의 메모리 공간을 할당하여 사용하는 기법을 말합니다. 동적으로 할당한 메모리는 사용이 끝나면 명시적으로 메모리를 해제해 줘야 합니다.

  • C 언어에서는 malloc() 또는 calloc() 함수로 data를 메모리에 할당하고, free() 함수로 메모리에서 해제합니다.
  • C++ 언어에서는 new 연산자로 data를 메모리에 할당하고, delete 연산자로 메모리에서 해제합니다.
  • 동적 메모리 할당은 힙(heap) 메모리 영역을 사용하므로 대용량 배열도 할당해 사용할 수 있습니다.

예시

#include <iostream>

int main()
{
	// 배열 크기 입력
    int sz;
    cin >> sz;
    
    // 동적 배열로 배열 포인터 초기화
    int* arr = new int[sz] {};
    
    // 동적 배열 원소 초기화
    for (int i = 0; i < sz; i++) {
        arr[i] = (i+1) * 10;
    }
    
    // 동적 배열 원소 출력
    for (int i = 0; i < sz; i++) {
    	cout << arr[i] << " ";
    }
    
    // 동적 배열을 메모리에서 해제
    delete [] arr;

    return 0;
}

// Result
// 5
// 10 20 30 40 50

Vector

std::vector란?

C++에서 C 스타일 동적 배열을 대체하는 가변 크기 컨테이너입니다.

  • 초기화 과정에 데이터의 크기를 지정하지 않아도 됩니다.
  • 크기를 확장할 수 있습니다.
  • 원소의 타입을 매개변수로 사용하는 클래스 템플릿이며, <vector>에 정의되어 있습니다.

1차원 vector 초기화 방법

#include <vector>

using namespace std;

int main()
{
	// 1차원 vector 초기화 방법
    vector<int> vec1; // empty vector
    
    vector<int> vec2(10); // 0 0 0 0 0 0 0 0 0 0
    
    vector<int> vec3(10, 1); // 1 1 1 1 1 1 1 1 1 1
    
    vector<int> vec4 {10, 20, 30, 40, 50}; // 10 20 30 40 50
    
    vector<int> vec5(vec4); // 10 20 30 40 50
    
    vector<int> vec6(vec4.begin(), vec4.begin() + 3); // 10 20 30
}

2차원 vector 초기화 방법

#include <vector>

using namespace std;

int main()
{
	// 2차원 vector 초기화 방법
    vector<vector<int>> mat1(2, vector<int>(3, 1));
    // 1 1 1
    // 1 1 1
    
    vector<vector<int>> mat2 {
        {1, 2, 3},
        {4, 5, 6}
    };
    // 1 2 3
    // 4 5 6
}

주요 멤버 함수

  • operator[] : 특정 위치 원소의 참조를 반환합니다.

  • front() : 첫 번째 원소의 참조를 반환합니다.

  • back() : 마지막 원소의 참조를 반환합니다.

  • push_back() : 마지막에 원소를 추가합니다.

  • pop_back() : 마지막 원소를 삭제하며, 마지막 원소를 반환하지 않습니다.

  • insert() : 특정 위치에 원소를 삽입합니다.

  • erase() : 특정 위치의 원소를 삭제합니다.

  • clear() : 모든 원소를 삭제합니다.

  • size() : 원소의 개수를 반환합니다.

  • empty() : 비어있으면 true를 반환합니다.

emplace()와 emplace_back()

emplace(), emplace_back()은 각각 insert(), push_back()과 동일한 기능을 수행하지만 동작 원리가 다릅니다.

  • insert(), push_back()은 임시 객체를 생성해 인자를 복사한 뒤 임시 객체를 컨테이너에 전달해 삽입하는 방식으로 동작합니다.
#include <vector>
#include <string>

using namespace std;

int main()
{
	vector<string> vec;
    
    // push_back()은 임시 string을 생성해 "hello"를 임시 string에 복사한 뒤, 임시 string을 vector에 전달해 삽입합니다.
    vec.push_back("hello");
}
  • emplace(), emplace_back()은 주어진 인자를 컨테이너로 전달해 컨테이너 내부에서 객체를 생성한 뒤 컨테이너에 삽입합니다. 그러므로, 임시 객체를 생성하지 않습니다.
#include <vector>
#include <string>

using namespace std;

int main()
{
	vector<string> vec;
    
    // emplace_back()은 임시 string을 생성하지 않고 vector 내부에서 "hello" 값을 갖는 string 객체를 생성한 뒤 vector에 삽입합니다.
    vec.emplace_back("hello");
}

결론적으로 emplace(), emplace_back()을 사용하면 불필요한 임시 객체의 생성과 객체의 복사를 피할 수 있습니다. 따라서, 더 효율적인 코드를 작성할 수 있습니다.

emplace(), emplace_back() 주의할 점

emplace 함수를 사용하는 이유는 불필요한 임시 객체 생성과 객체 복사를 피하기 위함입니다. 따라서, emplace 함수 인자로 객체 생성을 위한 인자를 직접 전달해야 합니다.

#include <vector>
#include <string>

using namespace std;

int main()
{
	// "hello"를 vec에 삽입하려는 경우
    
	vector<string> vec;
    
    // emplace_back()의 잘못된 사용법.
    string str = "hello";
    vec.emplace_back(str);
    
    // emplace_back()의 올바른 사용법.
    vec.emplace_back("hello");
}

포스팅을 마치며

이번에는 동적 배열과 vector에 대해 정리해 봤습니다.
emplace 함수에 대해 이해하는데 시간이 좀 걸렸네요.

Reference

  • 황선규. C++ 어서와! 자료 구조와 알고리즘은 처음이지?. Programmers.
  • std::vector::emplace. Cplusplus.
  • std::vector::emplace_back. Cplusplus.
  • Arthur O'Dwyer. Don't blindly prefer emplace_back to push_back. Github pages.
profile
매일 천천히 오래 달리고 싶어요

0개의 댓글