-
[c++] delete[] 가 포인터를 받아도 잘 동작하는 이유 2(associative array)카테고리 없음 2022. 11. 9. 16:44반응형
[c++] delete[] 가 포인터를 받아도 잘 동작하는 이유(over-allocate)
c++에서는 동적으로 객체를 생성 및 삭제를 시켜줄 때, new 그리고 delete 키워드를 쓰게 됩니다. 이때, new는 우리가 메모리를 할당하고, 생성자를 호출하게 되어, 그 사이즈나 크기를 명시해주게 됩
guru.tistory.com
이어, delete []를 사용했을 때, 사용되는 테크닉 "associative array"에 대해서 알아보겠습니다.
잠깐 정리하자면, delete[] 를 사용했을때, 얼마나 많은 소멸자를 호출해야 하는지 알 수 있게 하는 테크닉 중 하나인 "over-allocation"을 통해서 잠시나마 살펴보았습니다. 하지만 컴파일러는 associative array 라는 테크닉을 사용할 수 도 있는데, 이에 대해 알아보겠습니다.
associative-array - new
// Original code: Foo* pFoo = new Foo[n]; Foo* pFoo = (Foo*) operator new[] (n * sizeof(Foo)); // pFoo 자리에 메모리 할당 for (size_t i = 0; i < n; ++i) new(pFoo + i) Foo(); // n 만큼의 생성자 호출 arrayLengthAssociation.insert(pFoo, n); // 글로벌 객체인 AVL Tree(예시) 에 pointer 객체와 개수 n 맵핑
Associative array 에서는 히든 자료구조 형태의 arrayLengthAssociation(이름은 예시입니다)를 사용하여, 포인터와 객체를 연관시켜 메모리를 할당해주는 테크닉을 사용하고 있습니다. 마치 map 자료 구조 와 비슷하다는 느낌을 받았습니다.
associative-array - delete
// Original code: delete[] pFoo; size_t n = arrayLengthAssociation.lookup(pFoo); // pFoo 에 해당하는 객체가 몇개인지 확인 while (n-- != 0) (pFoo + n)->~Fred(); // 객체의 n 번 만큼 소멸자 호출 operator delete[] (pFoo); // 메모리 할당 해제
delete[ ]에서는 전역 객체인 arrayLengthAssociation에 pFoo에 해당하는 포인터의 개체가 몇 개인지 확인 후, 이를 통해 소멸자를 확인하고 있습니다.
CFront 라는 컴파일러는 AVL Tree를 사용해서, 이를 구현하고 있다고 합니다.
추가로, "over-allocation" 보다 "associative array"가 느리지만, delete pFoo 및 delete pFoo [ ]를 하든지 상관이 없다는 장점이 있습니다. 이는 arrayLengthAssociation에 저장된 포인터가 얼마만큼의 개수를 가졌는지 확인할 수 있다는 장점 때문에 그렇다고 할 수 있습니다.
정리
정리하자면, c++ 에서는 delete [ ] 키워드를 사용했을 때 알아서, 배열의 올바른 소멸자를 호출시켜주지만, 이면에는 "over-allocation" 이라든가, "associative array"라는 테크닉을 사용하는 것을 확인하였습니다. 실제로 이를 어셈블리를 통해서 확인하여, 어떻게 내부적으로 동작하는지 확인까지 하였습니다.
면접 질문에서 delete [ ] 가 어떻게 나오는지 설명해보세요!라고 했을 때, 당황하지 말고, 2가지 테크닉에 대해 설명하면 좋겠습니다 :)
[Reference]
http://www.cs.technion.ac.il/users/yechiel/c++-faq/num-elems-in-new-array-assocarray.html
https://pvs-studio.com/en/blog/posts/cpp/0973/
긴 글 읽어주셔서 감사합니다.
도움이 되셨거나, 잘못된 내용이 있다면 댓글 부탁드리겠습니다.
반응형