在 FreeMemory 中粘贴一些跟踪并将 main 更改为:
int main(int argc, char *argv[]) {
printf("map\n");
std::map<int, vec> z;
printf("vec\n");
vec x;
printf("pair\n");
std::pair<int,vec> y(1,x);
printf("insert\n");
z.insert(y);
printf("inserted 1\n");
y.first = 2;
printf("insert\n");
z.insert(y);
printf("inserted 2\n");
}
输出:
$ make mapinsert CXXFLAGS=-O3 -B && ./mapinsert
g++ -O3 mapinsert.cpp -o mapinsert
map
vec
pair
getMem n 0 ptr 0x6b0258
insert
getMem n 0 ptr 0x6b0268
getMem n 32 ptr 0x6b0278
getMem n 0 ptr 0x6b02a0
FreeMemory ptr 0x6b0268
inserted 1
insert
getMem n 0 ptr 0x6b0268
getMem n 32 ptr 0x6b02b0
getMem n 0 ptr 0x6b02d8
FreeMemory ptr 0x6b0268
inserted 2
FreeMemory ptr 0x6b0258
FreeMemory ptr 0x6b02d8
FreeMemory ptr 0x6b02b0
FreeMemory ptr 0x6b02a0
FreeMemory ptr 0x6b0278
因此,在您的 3 个 0 大小的分配中:
- 一种是将空向量复制到对中。
- 一种是将空向量的副本存储在地图中。
这两个显然是必要的。我不确定的是:
- 一种是在对 的调用中将向量复制到某处
insert
,这也在对插入的调用中被释放。
就好像insert
(或它在内部调用的东西)通过值而不是通过引用来获取其参数,或者insert
在分配新地图节点之前的某个时间显式地将副本复制到自动变量中。目前,启动调试器对我来说很费力,我会把它留给其他人。
编辑:谜团解开了。insert
需要 a std::pair<const int, vec>
,而不是std::pair<int, vec>
. 空向量的额外副本是因为您构造的对必须转换为(另一个)临时对象,然后将该临时对象的引用传递给insert
. std::pair 有一个构造函数模板,可以让你摆脱几乎任何事情。20.2.2/4:
template<class U, class V> pair(const pair<U,V> &p);
效果:从参数的相应成员初始化成员,根据需要执行隐式转换。
我还观察到,在我的实现中,vec x;
不调用getMem
,而是调用vec x(0);
。所以实际上:
z[1] = vec();
代码更少,并剥夺了您制作额外副本的机会(尽管它改为调用operator=
)。至少对我来说,它仍然会进行 2 个 0 大小的分配。
C++ 标准定义operator[]
返回涉及调用的指定表达式的结果insert
。我不确定这是否意味着 的效果operator[]
“好像”make_pair
并被insert
调用(也就是说,标准与指定源必须是什么一样好operator[]
),或者只是返回的值与指定的表达式会产生。如果是后者,那么也许一个实现可以使用单个 0 大小的分配来完成。但是,如果不首先创建包含映射类型的对,肯定map
无法保证创建条目的方法,因此应该预期 2 次分配。或者更准确地说,所需映射值的 2 个副本:复制 0 大小的向量会产生 0 大小的分配这一事实取决于实现。
因此,如果您遇到的情况是复制该值非常昂贵,但对于默认构造却非常便宜(例如具有大量元素的容器),那么以下内容可能有用:
std::map<int, vec> z;
vec x(1000);
z[1] = x;
// i.e. (*(z.insert(std::pair<const int, vec>(1,vec())).first)).second = x;
进行 2 次大小为 4000 的分配和 2 次大小为 0 的分配,而:
std::map<int, vec> z;
vec x(1000);
z.insert(std::pair<const int, vec>(2, x));
使 3 的大小为 4000 而没有大小为 0。最终大小足够大,以至于第一个代码中的额外分配比第二个代码中的额外复制便宜。
C++0x 中的移动构造函数可能会对此有所帮助,我不确定。