我有一个类X,我想将其放入std :: map类型的STL映射中。 STL映射需要将X存储在某个内存中,所以我正在寻找一种有效的(运行时和内存)方式来创建X并将其存储在地图中。
我注意到以下代码,其中x是X类型的对象,stlMap是std :: map类型的地图:
stlMap["test"] = x;
以下结果被称为:
为什么要创建这么多X对象?
这是时间和记忆的低效使用吗?
有没有更好的方法将对象放入地图?也许将地图更改为字符串映射到x *?
答案 0 :(得分:5)
尝试stlMap.insert( map<string, X>::value_type("test", x) )
:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class X
{
public:
X() { cout << "X default constructor" << endl; }
~X() { cout << "X destructor" << endl; }
X( const X& other ) { cout << "X copy constructor" << endl; }
X& operator=( const X& other ) { cout << "X copy-assignment operator" << endl; }
int x;
};
int main()
{
X x;
map< string, X > stlMap;
cout << "INSERT BEGIN" << endl;
stlMap.insert( map< string, X >::value_type( "test", x ) );
cout << "INSERT END" << endl;
stlMap.clear();
cout << "ASSIGN BEGIN" << endl;
stlMap["test"] = x;
cout << "ASSIGN END" << endl;
return 0;
}
在我的g ++上将事情归结为:
答案 1 :(得分:3)
STL容器具有复制语义,因此您观察到的是典型的。
你可以改用指针,但是你可以通过使用智能指针来避免相关的内存管理痛苦(以少量开销为代价)。
答案 2 :(得分:1)
将此作为参考:
#include <iostream>
#include <map>
class X
{
public:
X() { std::cout << "Default Construct\n";}
~X() { std::cout << "Destroy\n";}
X(X const&) { std::cout << "Copy Construct\n";}
X& operator=(X const&) { std::cout << "Assignment\n";}
};
int main()
{
std::map<int,X> store;
X x;
X y;
std::cout << "Inserting x\n";
store[1] = x;
std::cout << "Finished Insert\n";
std::cout << "Inserting y\n";
store[1] = y;
std::cout << "Finished Insert\n";
}
运行我们得到以下输出:
Default Construct Building X
Default Construct Building Y
Inserting x ---- Start of an insert
Default Construct -------- Work to insert an item that is not in the map
Copy Construct
Copy Construct
Destroy
Destroy -------- Finished work to insert a new item
Assignment Assign x into the internal object
Finished Insert ---- Done
Inserting y ---- Start of an insert
Assignment Assign y onto the internal object.
Finished Insert ---- Done
Destroy Destroy y
Destroy Destroy x
Destroy Destroy map containing one X
答案 3 :(得分:0)
STL的工作原理是复制和分配。因此需要进行一些复制和分配。关于为什么这么多的问题,找到这种方法的一种方法是将断点放在X
代码中的适当位置,并在调试器中运行该程序。
以当前方式,std::map
正在为X
进行内存管理。如果切换到使用X*
,则必须自己进行内存管理。我发现前者适合大多数情况。
答案 4 :(得分:0)
启用优化时,构造和销毁的顺序是否不同?许多编译器在优化时可以省略这些语句中涉及的临时对象。我猜想在优化时输出会涉及更少的对象。
C ++ 0x通过移动构造函数大大改善了这种情况。如果您的类X有一个移动构造函数(看起来像X x(X&& m) { ... }
),那么您可以将语句更改为stlMap["test"] = std::move(x);
。该语句基本上等同于构造单个X然后将其移动到所有权如果你没有找到C ++ 0x移动语义的一些文章,这是有用的东西。