n차원의 배열을 표현하기 위해 구조체 정의

struct Address {
	int level;
	void* next;
};

만약 3차원 배열을 정의한다고 하면, 총 4개의 레벨(0~3)이 만들어지며 n-1레벨에는 데이터를 저장할 배열, 0~n-2 레벨에는 다음 Address 구조체의 배열을 가리키는 포인터가 저장된다.

C++에서 구조체는 모든 멤버 변수, 멤버 함수가 디폴트로 public인 클래스라고 생각하면 된다.

임의의 차원을 다룰떄는 재귀 함수를 이용하는 것이 좋다. 재귀 함수로 프로그램을 설계할때는 다음 단계로 넘어가는 조건과 재귀 호출이 종료되는 조건을 파악하는 것이 중요하다. 이 예제에서의 탈출조건은 배열의 레벨이 (dim -1)이 되는 순간이다. 이때 정해진 크기의 int배열을 생성하면서 재귀 호출을 종료한다.

// address 를 초기화 하는 함수이다. 재귀 호출로 구성되어 있다.
void initialize_address(Address* current) {
	if (!current) return;
	if (current->level == dim - 1) { // 두 번째 질문 (종료 조건)
		current->next = new int[size[current->level]];
		return;
	}
	current->next = new Address[size[current->level]];
	for (int i = 0; i != size[current->level]; i++) { // 다음 단계로 넘어가는 과정
		(static_cast<Address*>(current->next) + i)->level = current->level + 1;

		initialize_address(static_cast<Address*>(current->next) + i);
	}
}

이러한 방식으로 함수를 재귀호출하게 된다면 '깊이 우선 탐색'을 하는 것과 비슷하게 동작한다. 생성자는 위부터 아래로 생성하였으니, 소멸자는 아래부터 위로 소멸시켜나가야 한다.

void delete_address(Address *current) {
  if (!current) return;
  for (int i = 0; current->level < dim - 1 && i < size[current->level]; i++) {
    delete_address(static_cast<Address *>(current->next) + i);
  }

  if (current->level == dim - 1) {
    delete[] static_cast<int *>(current->next);
  }

  delete[] static_cast<Address *>(current->next);
}

마지막 레벨에는 int 들이 정의되어 있기에 int*로 캐스팅해서 delete하고, 나머지 레벨은 address로 캐스팅하여 delete한다.

항상 유의할 점은 소멸자에서 동적으로 할당된 모든 것들을 정리해줘야 한다. 재귀호출로 생성한 메모리 구조만을 소멸해야 되는 것이 아니라 size역시 동적으로 할당된 것이므로 꼭 해제해줘야 한다.