C++标准规定对象在创建时会调用构造函数,在离开作用域的时候会自动调用析构函数。但是有些时候我们需要在一块特定的内存上构建出一个对象,这个时候就需要显式调用构造函数和析构函数。最常见的是stl中各种容器使用allocator来管理对象。
struct Obj { Obj() : m_val(100) { std::cout << "Obj construct" << std::endl; } ~Obj() { std::cout << "Obj destroy" << std::endl; } int m_val; }; int main(int argc, char** argv) { std::allocator<Obj> al; Obj* p = al.allocate(1); al.construct(p); std::cout << p->m_val << std::endl; al.destroy(p); al.deallocate(p, 1); return 0; }
al.construct()显式调用了构造函数 new (p) T()。al.destroy()显式调用了析构函数 p->~T()。甚至可以这么做:
struct Base { Base(int v) : m_int(v) {} virtual ~Base() {} virtual void print() = 0; int m_int; }; struct Derive : Base { Derive(double v) : Base(static_cast<int>(v)), m_double(v) {} virtual ~Derive() {} virtual void print() { std::cout << "int:" << m_int << " double:" << m_double << std::endl; } double m_double; }; int main(int argc, char** argv) { char mem[sizeof(Derive)]; // 申请内存 Base* p = reinterpret_cast<Derive*>(&mem); new (p) Derive(12.34); // 原地构建对象 p->print(); p->~Base(); // 原地析构对象 return 0; }
当然上面的例子有些做作。在讨论实际项目中何时会用到显式构造/析构之前先来看一下C++11标准中有关union的规定.在c++03之前,union的成员只能是pod类型(任何有non-trivial构造/析构的类都是pod!).例如
struct Pod { }; struct NotPod { NotPod() {} virtual ~NotPod(){} }; union U { Pod p1; NotPod P2; // c++03 error! };
C++11放开了这个限制,任何有non-trivial构造/析构的类型也能成为union类型的成员。这是的union类型变得更加强大:
union Dynamic
{
Dynamic () {} // 必须显示定义
~Dynamic () {} // 必须显示定义 std::string m_s; std::map<int, int> m_map; }; Dynamic dy; dy.m_s = "abc"; // not initialization error!
注意Dynamic的构造和析构必须显示定义。C++11标准规定,如果union的成员类型有non-trivial构造/析构/拷贝/拷贝复制函数,那么必须显示定义该union相应的函数,编译器不会合成默认版本。当dy对象创建时,string对象和map对象的并未被构造。如果要使用它们,必须显示构造。
new (&dy.m_s) std::string("abcdef"); dy.m_s.~basic_string(); new (&dy.m_map) std::map<int, int>(); dy.m_map.~map<int, int>();
附上完整的Dynamic例子:
#include <iostream> #include <string> #include <map> class Dynamic { public: enum Type { INT, STRING, OBJECT }; public: Dynamic() : m_type(OBJECT) { new (&m_data.m_objs) std::map<Dynamic, Dynamic>(); } Dynamic(const char* p) : m_type(STRING) { new (&m_data.m_string) std::string(p); } Dynamic(int val) : m_type(INT) { m_data.m_int = val; } Dynamic(const Dynamic& obj) { m_type = obj.m_type; if (m_type == STRING) { new (&m_data.m_string) std::string(obj.m_data.m_string); } else if (m_type == OBJECT) { new (&m_data.m_objs) std::map<Dynamic, Dynamic>(obj.m_data.m_objs); } else if (m_type == INT) { m_data.m_int = obj.m_data.m_int; } } ~Dynamic() { destory(); } bool operator< (const Dynamic& obj) const { if (m_type == obj.m_type) { if (m_type == INT) return m_data.m_int < obj.m_data.m_int; else if (m_type == STRING) return m_data.m_string < obj.m_data.m_string; } return false; } Dynamic& operator[] (const Dynamic& obj) { return m_data.m_objs[obj]; } Dynamic& operator= (const Dynamic& obj) { if (&obj != this) { destory(); m_type = obj.m_type; if (obj.m_type == INT) { m_data.m_int = obj.m_data.m_int; } else if (obj.m_type == STRING) { new (&m_data.m_string) std::string(obj.m_data.m_string); // 显式构造 } else { new (&m_data.m_objs) std::map<Dynamic, Dynamic>(obj.m_data.m_objs); // 显式构造 } } return *this; } int asInt() const { return m_data.m_int; } std::string asString() const { return m_data.m_string; } private: void destory() { if (m_type == STRING) { m_data.m_string.~basic_string(); // 显式析构 } else if (m_type == OBJECT) { m_data.m_objs.~map<Dynamic, Dynamic>(); // 显式析构 } } private: int m_type; union U { U() {} ~U() {} U(const U&) {} int m_int; std::string m_string; std::map<Dynamic, Dynamic> m_objs; }m_data; }; int main() { Dynamic d; d["a"] = "12"; d["b"] = "34"; d["c"] = "xx"; d["a"] = 56; std::cout << d["a"].asInt() << std::endl; std::cout << d["b"].asString() << std::endl; std::cout << d["c"].asString() << std::endl; return 0; }
参考资料
https://github.com/facebook/folly/