我已经设置了这个例子:
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
在这里创建副本?
答案 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