C++显式调用构造函数和调用析构函数

C++标准规定对象在创建时会调用构造函数,在离开作用域的时候会自动调用析构函数。但是有些时候我们需要在一块特定的内存上构建出一个对象,这个时候就需要显式调用构造函数和析构函数。最常见的是stl中各种容器使用allocator来管理对象。

C++显式调用构造函数和调用析构函数
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;
}
C++显式调用构造函数和调用析构函数

al.construct()显式调用了构造函数 new (p) T()。al.destroy()显式调用了析构函数 p->~T()。甚至可以这么做:

C++显式调用构造函数和调用析构函数
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++显式调用构造函数和调用析构函数

 

当然上面的例子有些做作。在讨论实际项目中何时会用到显式构造/析构之前先来看一下C++11标准中有关union的规定.在c++03之前,union的成员只能是pod类型(任何有non-trivial构造/析构的类都是pod!).例如

C++显式调用构造函数和调用析构函数
struct Pod { };

struct NotPod { NotPod() {} virtual ~NotPod(){} };

union U
{
    Pod p1;
    NotPod P2;  // c++03 error!
};
C++显式调用构造函数和调用析构函数

C++11放开了这个限制,任何有non-trivial构造/析构的类型也能成为union类型的成员。这是的union类型变得更加强大:

C++显式调用构造函数和调用析构函数
union Dynamic
{
Dynamic () {}      // 必须显示定义
~Dynamic () {}     // 必须显示定义
    std::string m_s;
    std::map<int, int> m_map;
};
    Dynamic dy;
    dy.m_s = "abc";    //  not initialization error!
C++显式调用构造函数和调用析构函数

注意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例子:

C++显式调用构造函数和调用析构函数
#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;
}
C++显式调用构造函数和调用析构函数

参考资料

 https://github.com/facebook/folly/

C++显式调用构造函数和调用析构函数,布布扣,bubuko.com

C++显式调用构造函数和调用析构函数

上一篇:选择一本C++教材


下一篇:python实现简单爬虫功能