C++ 如何使stl映射只构造/销毁一次插入的对象

C++ 如何使stl映射只构造/销毁一次插入的对象,c++,stl,C++,Stl,我发现了一个关于stl映射的非常有偏见的事实。由于某些原因,我无法使插入到地图中的对象只构造/破坏一次 例如: struct MyObject{ MyObject(){ cout << "constructor" << endl; } ~MyObject(){ cout << "destructor" << endl; } }; int main() { std::map<

我发现了一个关于stl映射的非常有偏见的事实。由于某些原因,我无法使插入到地图中的对象只构造/破坏一次

例如:

struct MyObject{
    MyObject(){
        cout << "constructor" << endl;
    }
    ~MyObject(){
        cout << "destructor" << endl;
    }
};
int main() {
    std::map<int, MyObject> myObjectsMap;
    myObjectsMap[0] = MyObject();
    return 0;
}
如果我这样做:

typedef std::pair<int, MyObject> MyObjectPair;
myObjectsMap.insert( MyObjectPair(0,MyObject()));

我正在插入负责自己内存分配的对象,因此当被破坏时,它们会自行清理,多次被破坏会给我带来一些麻烦。

这就是
map
和其他容器的工作方式,你无法回避它。例如,这就是为什么不能在集合中使用
std::auto_ptr
的原因。

我建议您添加一个复制构造函数-我认为这就是用于“缺失”构造的原因

代码:


std::map
可以根据需要制作尽可能多的对象副本。这是实现定义的,您对此没有控制权。顺便说一下,您注意到的“缺失”构造可能是为了调用复制构造函数,而您没有定义它


但是,您可以使用flyweight,这样构造一个对象实际上是从一个预先存在的对象池中获取一个现有对象,而销毁一个对象则什么也不做。池从不释放其对象,但始终在所有对象上保持句柄。这样,您的内存使用从开始到结束都非常大,但在程序的整个生命周期中变化不大。

要能够在标准容器中使用,您的对象必须是可复制和可分配的。如果您的对象不符合此要求,则可能会出现问题

也就是说,如果(如示例代码所示)您只需要在地图中插入一个默认构造的对象,您可以使用操作符[]来实现其副作用:

// Insert default constructed MyObject at key 0
myObjectsMap[0];
编辑


我对你的问题不太清楚,但是如果你不清楚构造的对象的数量,并且认为构造函数/析构函数不匹配,那么请注意,编译器将提供一个副本构造函数,它不会登录到
std::cout
,因为你没有提供用户声明的构造函数。

当你说myObjectsMap[0]时,您正在调用MyObject的默认构造函数。这是因为[0]中还没有任何内容,而您刚刚访问了它

当你点击MyObject()时;您正在使用默认构造函数创建临时MyObject实例

因为您允许编译器定义复制构造函数,所以您看到的析构函数消息多于构造函数消息。(可以只有一个析构函数,但可以有许多构造函数,这与建造房屋不同。)如果对象不应以这种方式复制,则可能需要声明私有复制构造函数和复制赋值运算符

使用以下代码调用默认构造函数和复制构造函数两次

myObjectsMap[0] = MyObject();
执行此操作时:

myObjectsMap.insert( MyObjectPair(0,MyObject()));
调用默认构造函数一次,复制构造函数三次

您可能应该使用指针作为映射值,而不是对象本身,特别是我建议查看共享的\u ptr

note: tests were done using GCC 3.4.5 on a Windows NT 5.1 machine.

我想我将切换到一个向量,并在地图中保留指针。我希望能够有一个构造和一个破坏,就像我使用向量一样。向量v;v、 向后推(MyObject())//只生成一个构造和销毁。您测试过什么
myObjectsMap[0]实际上是这样吗?嗯,不是这样,我实际上使用的是insert方法,它的开销较小,但产生的副本仍然比我预期的多。无论哪种方式,我都认为我将继续使用向量,并且只将映射用于指针。上面的帖子很清楚到底发生了什么。很高兴知道。在MSVC
map::operator[]
中,如果已经没有键,则调用
map::insert
,因此不进行简化here@Alberto,我也有同样的问题,我将使用
boost::shared\u ptr
作为
map::mapped\u type
std::map
不提供创建新条目的非复制接口。我建议在这里使用共享指针-
std::map
// Insert default constructed MyObject at key 0
myObjectsMap[0];
myObjectsMap[0] = MyObject();
myObjectsMap.insert( MyObjectPair(0,MyObject()));
note: tests were done using GCC 3.4.5 on a Windows NT 5.1 machine.