破坏和分配的顺序

时间:2016-05-29 18:24:49

标签: c++ c++11 memory

我正在研究一个Entity类,它需要通过setter方法提供对其数据成员的访问,setter方法在存储之前检查一个值(检查代码未显示)。 Select类是存储的类型之一,它需要在销毁时进行一些非常具体的清理:

#include<memory>
#include <iostream>
using namespace std;

class Select {
    int i, j;

    friend class Entity;

public:
    Select(int a, int b) : i{a}, j{b} { }

    ~Select() {
        cout << "destroying " << i << j << endl;
    }

protected:
    Select() { };
};

class Entity {

    Select select_;

public:
    void select_setter(const Select &select) {
        cout << "to be assigned... " << select.i << select.j << endl;
        select_ = select;
    }

    static shared_ptr<Entity> create(const Select &s) {
        auto sp = make_shared<Entity>(Entity{});
        sp->select_setter(s);
        return sp;
    }
};

此块演示了我希望如何使用Entity类型:

int main() {
    auto sp = Entity::create({1, 1});    
    sp->select_setter({2, 2});
    sp->select_setter({3, 3});    
    cout << "the end" << endl;
    return 0;
}

这是输出:

destroying 00
to be assigned... 11
destroying 11
to be assigned... 22
destroying 22
to be assigned... 33
destroying 33
the end
destroying 33

为什么33被摧毁两次,但00,11和22只被摧毁一次?

1 个答案:

答案 0 :(得分:3)

当你想分析这样的构造函数/析构函数行为时,我的建议是:

  • 记录所有构造函数(默认构造函数,复制构造函数,其他构造函数)
  • 记录所有析构函数
  • 要知道谁是谁的对象的日志地址......

通过添加更多输出,并实施SelectEntity副本构造函数,您可以获得:

Before auto sp = Entity::create({1, 1});
In Select 1 1 ctor 0x7fff85e31b80                    // That's Select temporary object {1,1} being created
In Select default ctor 0x7fff85e31b40                // That's Entity attribute being created before Entity ctor is entered below
In Entity ctor 0x7fff85e31b40                        // That's Entity ctor for Entity{} you create
In Select default ctor 0x2248028                     // That's Entity attribute being created before Entity ctor is entered below
In Entity copy ctor copy 0x7fff85e31b40 to 0x2248028 // That's copying Entity{} object as the shared_ptr attribute
In Entity dtor 0x7fff85e31b40                        // That's Entity{} being destroyed
destroying 00 0x7fff85e31b40                         // That's Entity{}'s Select attribute being destroyed. Is 00 but could be anything else (not initialized)
to be assigned... 11
destroying 11 0x7fff85e31b80                         // That's Select temporary object {1,1} being destroyed

Before sp->select_setter({2, 2});
In Select 2 2 ctor 0x7fff85e31b70                    // That's Select temporary object ({2,2})
to be assigned... 22
destroying 22 0x7fff85e31b70                         // That's Select temporary object ({2,2}) being destroyed

Before sp->select_setter({3, 3});
In Select 3 3 ctor 0x7fff85e31b80                    // That's Select temporary object ({3,3})
to be assigned... 33
destroying 33 0x7fff85e31b80                         // That's Select temporary object ({2,2}) being destroyed

the end
In Entity dtor 0x2248028                             // That's Entity stored in the shared_ptr object being destroyed
destroying 33 0x2248028

这完全有道理......

只需使用此代码:

#include <memory>
#include <iostream>
using namespace std;

class Select {
    int i, j;

    friend class Entity;

public:
    Select(int a, int b) : i{a}, j{b} { std::cout << "In Select " << a << " " << b << " ctor" << std::hex << "0x" << this << std::endl;}

    ~Select() {
        cout << "destroying " << i << j << std::hex << "0x" << this << endl;
    }

    Select( const Select& e ) {
        i = e.i; j = e.j;
        std::cout << "In Select copy ctor copy " << std::hex << "0x" << &e << " to " << std::hex << "0x" << this << std::endl;
    }

    Select() { std::cout << "In Select default ctor" << std::hex << "0x" << this << std::endl; }

};

class Entity {

    Select select_;

public:

    Entity() { std::cout << "In Entity ctor " << std::hex << "0x" << this << std::endl; }
    Entity( const Entity& e ) {
         select_ = e.select_;
         std::cout << "In Entity copy ctor copy " << std::hex << "0x" << &e << " to " << std::hex << "0x" << this << std::endl;  }

    ~Entity() { std::cout << "In Entity dtor " << std::hex << "0x" << this << std::endl; }

    void select_setter(const Select &select) {
        cout << "to be assigned... " << select.i << select.j << endl;
        select_ = select;
    }

    static shared_ptr<Entity> create(const Select &s) {
        auto sp = make_shared<Entity>(Entity{});
        sp->select_setter(s);
        return sp;
    }
};

int main() {
    std::cout << "Before auto sp = Entity::create({1, 1});" << std::endl;
    auto sp = Entity::create({1, 1});
    std::cout << "Before sp->select_setter({2, 2});" << std::endl;
    sp->select_setter({2, 2});
    std::cout << "Before sp->select_setter({3, 3});" << std::endl;
    sp->select_setter({3, 3});
    cout << "the end" << endl;
    return 0;
}