为什么在插入set后会删除对象?

时间:2013-06-12 12:32:48

标签: c++ c++11

我已经设置了这个例子:

class UsefulClass {
public: 
        int id;
        const bool operator< (const UsefulClass &other) const {
                return this->id > other.id;
        }
        UsefulClass(int _id): id(_id) {
                std::cout << "constructing " << id << std::endl;
        }
        ~UsefulClass() {
                std::cout << "destructing " << id << std::endl;
        }
};
std::set<UsefulClass> set;
void create() {
        UsefulClass object_1(1);
        UsefulClass object_2(2);
        set.insert(object_1);
        set.insert(std::move(object_2));

        std::cout << "create end" << std::endl;
}
int main() {
        create();
        std::cout << "main end" << std::endl;
}

我希望在程序结束时删除set时,对象会被破坏一次。但是对象被删除了两次:

constructing 1
constructing 2
create end
destructing 2
destructing 1
main end
destructing 1
destructing 2

为什么set.insert在这里创建副本?

5 个答案:

答案 0 :(得分:4)

set中的对象与create()的本地对象不同。 set中的那些是使用复制构造函数和移动构造函数而不是构造函数UsefulClass(int)构造的,因此您不会看到它们的构造。当函数create()返回时,本地对象被销毁,然后set结束后main中的对象在全局清理时被销毁。

答案 1 :(得分:2)

object_1和object_2是在堆栈上创建的,一旦create()函数结束就会被销毁。它们需要复制到由set的allocator管理的内存中。

如果重新定义复制构造函数,要跟踪其执行情况,您会注意到它在两个插入处都被调用。

答案 2 :(得分:1)

Rule of 3适用于您的情况,如果您从dtor打印并想要有意义的跟踪,您应该复制(也可能移动)ctor。

如果你这样做,那么输出就会有意义,事情应该正确配对。

答案 3 :(得分:0)

因为您的对象在插入集合时会被复制。因此,当create()函数返回时,两个本地对象将被销毁。 main结束后,集合中的两个副本将被销毁,从而导致第二对消息。

答案 4 :(得分:0)

为了说明每个人在我之前说过的话,只需创建这个简单的例子(它使用一个新的复制构造函数来使用集合,并在每次执行构造函数时使用全局变量生成不同的id - - 已经过测试,所以你可以把它放在一个文件中并编译):

#include <iostream>
#include <string>
#include <set>

using namespace std;

class UsefulClass {
    static int instance;
public:
    int id;
    int i;

    const bool operator<(const UsefulClass &other) const {
        return id < other.id;
    }

    UsefulClass(int i){
        id = instance++;
        this->i = i;
        cout    << "constructing "
            << id
            << ":"
            << this->i
            << endl;
    }

    UsefulClass(const UsefulClass& other) {
        id = instance++;
        i = other.i;
        cout    << "constructing "
            << id
            << ":"
            << i
            << endl;
    }

        ~UsefulClass(){
        cout    << "destructing "
            << id
            << ":"
            << i
            << endl;
    }
};

int UsefulClass::instance = 0;

std::set<UsefulClass> myset;

void create() {
        UsefulClass object_1(1);
        UsefulClass object_2(2);
        myset.insert(object_1);
    /* please, explain what you mean with std::move, or which move
     * have you used for the next statement.  All i have is
     * std::move(... ) for strings, but you have not defined
     * string UsefulClass::operator string();
     */
        myset.insert(/*std::move*/(object_2));

        cout    << "create end"
        << endl;
}

int main() {
        create();
        cout    << "main end"
        << std::endl;
}

因此,每当您创建一个UsefulClass对象时,您将获得不同的实例ID,并且当您插入到集合中时,您会看到它们被复制为新实例。您将看到每个对象何时被创建以及何时被删除。

$ pru
constructing 0:1
constructing 1:2
constructing 2:1
constructing 3:2
create end
destructing 1:2
destructing 0:1
main end
destructing 2:1
destructing 3:2