[C++] placement new
Updated:
개요
- 지정한 메모리에 객체를 초기화
- 메모리 할당과 초기화를 분리하기 위한 기법
- 메모리 할당 시점에 타입을 정할 수 없거나 초기화 시점을 지정하고 싶은 경우에 사용
- pool(connection, momory, …), 다형성 등
주의사항
- placement new 사용 시 delete 대신 소멸자를 직접 호출하고 메모리 해제는 할당한 곳에서 할당 방법에 따른 적절한 해제를 해야함
- delete의 경우 객체 소멸과 operator delete를 통한 메모리 해제 수행
- placement new에서 할당한 메모리가 아니기 때문에 객체 소멸만 책임을 지는 것이 논리적
예제
- 코드
#include <cstdlib> #include <iostream> #include <string> using namespace std; class Base { protected: int i; public: Base(int i) : i(i) { cout << "Base()" << endl; } virtual ~Base() { cout << "~Base()" << endl; } virtual void Print() = 0; }; class Derived_1 : public Base { private: char c; public: Derived_1(int i, char c) : Base(i), c(c) { cout << "Derived_1()" << endl; } virtual ~Derived_1() { cout << "~Derived_1()" << endl; } virtual void Print() override { cout << this->i << ", " << this->c << endl; } void Func1() { cout << "Func1()" << endl; }; }; class Derived_2 : public Base { private: string s; public: Derived_2(int i, string s) : Base(i), s(s) { cout << "Derived_2()" << endl; } virtual ~Derived_2() { cout << "~Derived_2()" << endl; } virtual void Print() override { cout << this->i << ", " << this->s << endl; } void Func2() { cout << "Func2()" << endl; }; }; void malloc_test() { cout << "--- " << __func__ << " start ---" << endl; Base *base = static_cast<Base *>(malloc(sizeof(Base) * 1)); cout << "~~~" << endl; Derived_1 *derived = new (base) Derived_1(1, 'a'); base->Print(); derived->Print(); static_cast<Derived_1 *>(base)->Func1(); base->~Base(); free(base); cout << "--- " << __func__ << " end ---" << endl; } void calloc_test() { cout << "--- " << __func__ << " start ---" << endl; Base *base = static_cast<Base *>(calloc(1, sizeof(Base))); cout << "~~~" << endl; Derived_1 *derived = new (base) Derived_1(1, 'b'); base->Print(); derived->Print(); static_cast<Derived_1 *>(base)->Func1(); base->~Base(); free(base); cout << "--- " << __func__ << " end ---" << endl; } void operator_new_test_1() { cout << "--- " << __func__ << " start ---" << endl; Base *base = static_cast<Base *>(operator new(sizeof(Base))); cout << "~~~" << endl; Derived_2 *derived = new (base) Derived_2(1, "aaa"); base->Print(); derived->Print(); static_cast<Derived_2 *>(base)->Func2(); base->~Base(); operator delete(base); cout << "--- " << __func__ << " end ---" << endl; } void operator_new_test_2() { cout << "--- " << __func__ << " start ---" << endl; const int size = 3; unsigned char pool[sizeof(Derived_2) * size]; for (int i = 0; i < size; ++i) { new (pool + (sizeof(Derived_2) * i)) Derived_2(i, "a"); } for (int i = 0; i < size; ++i) { reinterpret_cast<Derived_2 *>(pool + sizeof(Derived_2) * i)->Print(); } for (int i = 0; i < size; ++i) { reinterpret_cast<Derived_2 *>(pool + sizeof(Derived_2) * i) ->~Derived_2(); } cout << "--- " << __func__ << " end ---" << endl; } int main() { malloc_test(); cout << endl; calloc_test(); cout << endl; operator_new_test_1(); cout << endl; operator_new_test_2(); return 0; }
- 실행 결과
--- malloc_test start --- ~~~ Base() Derived_1() 1, a 1, a Func1() ~Derived_1() ~Base() --- malloc_test end --- --- calloc_test start --- ~~~ Base() Derived_1() 1, b 1, b Func1() ~Derived_1() ~Base() --- calloc_test end --- --- operator_new_test_1 start --- ~~~ Base() Derived_2() 1, aaa 1, aaa Func2() ~Derived_2() ~Base() --- operator_new_test_1 end --- --- operator_new_test_2 start --- Base() Derived_2() Base() Derived_2() Base() Derived_2() 0, a 1, a 2, a ~Derived_2() ~Base() ~Derived_2() ~Base() ~Derived_2() ~Base() --- operator_new_test_2 end ---