【发布时间】:2013-11-04 10:31:45
【问题描述】:
有人可以帮我理解 std::map 容器是如何实现的吗?我有一个包含原子成员的类,我不需要调用复制构造函数,因此我使用 c++11 删除运算符来抑制复制构造函数的隐式生成。
MyCalss(const MyClass& a) = delete;
这在我的 windows 版本中运行良好,但是在 Linux 中我收到一个错误,通知我 std::map 类的 [] 运算符正在尝试调用已删除的函数。
Windows VS2013 和 Linux GCC 4.7.x 的 map 实现之间似乎存在重大差异。这让我做了一个关于如何将对象插入地图的实验。
我写了这个小例子程序:
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <iostream>
#include <string>
using namespace std;
class TestItem {
public:
TestItem () {
_name = "TestItem" + id();
cout << "Constructing " << _name << endl;
}
TestItem (const TestItem & other) {
_name = "TestItem " + id();
cout << "Copying " << other._name << " to new " << _name <<endl;
}
string id()
{
static int id = 0;
char buf[2];
sprintf_s(buf, "%d", id++);
return string(buf);
}
~TestItem(){
cout << "Destroying " << _name << endl;
}
void doStuff()
{
// stub
}
string _name;
};
void run()
{
cout << "making new obj" << endl;
TestItem a;
cout << endl << endl;
map<string, TestItem> TestItemMap;
cout << "Makeing new obj as part of a map insert" << endl;
TestItemMap["foo"].doStuff();
cout << endl << endl;
cout << "adding a value to the map" << endl;
TestItemMap["new foo key"] = a;
cout << endl << endl;
cout << "looking up a value that has already been inserted" << endl;
TestItem& b = TestItemMap["foo"];
cout << endl << endl;
}
int main(int argc, char** argv)
{
run();
}
在 Windows 中,当我运行这个程序时,我得到以下输出:
making new obj
Constructing TestItem0
Making new obj as part of a map insert
Constructing TestItem1
adding a value to the map
Constructing TestItem2
looking up a value that has already been inserted
Destroying TestItem1
Destroying TestItem0
Destroying TestItem0
这是我在内部编写时希望看到的
TestItemMap["foo"].doStuff();
我希望地图会创建一个新的 TestItem 实例,然后通过将树节点内部链接到新的 TestItem 将其插入 RedBlack 树。
但是,当我在 Linux 中运行相同的代码时,结果却大不相同
making new obj
Constructing TestItem0
Making new obj as part of a map insert
Constructing TestItem1
Copying TestItem1 to new TestItem2
Copying TestItem2 to new TestItem3
Destroying TestItem2
Destroying TestItem1
adding a value to the map
Constructing TestItem4
Copying TestItem4 to new TestItem5
Copying TestItem5 to new TestItem6
Destroying TestItem5
Destroying TestItem4
looking up a value that has already been inserted
Destroying TestItem0
Destroying TestItem3
Destroying TestItem0
这将向我表明 [] 运算符正在创建 TestItem 的新实例,然后调用外部 map.insert() 函数,然后销毁新创建的 TestItem,这仅解释了对复制构造函数的调用之一. gcc中的c++ stdlib真的这么低效吗?
人们使用一些标准技巧来解决这个问题吗?
【问题讨论】:
-
GCC默认使用的标准库叫做libstdc++,是开源的。也附带 GCC 源代码。如果您想知道它是如何实现的,只需下载源代码并查看即可。
-
您正在比较启用优化的两个编译,不是吗?
-
至于你的问题,我会更好奇说明
TestItem0被破坏的两行行。 -
sprintf_s 不是标准的,所以它不能在 linux 上编译。你用了什么代码?
-
@JoachimPileborg 这是用于
TestItemMap["new mooky key"] = a;的显然未考虑的赋值运算符的结果,我敢打赌 OP 没有看到它的到来。
标签: c++ linux windows gcc c++11