Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 与VS2013相比,gcc 4.7.2中的std::map实现效率非常低?_C++_Linux_Windows_Gcc_C++11 - Fatal编程技术网

C++ 与VS2013相比,gcc 4.7.2中的std::map实现效率非常低?

C++ 与VS2013相比,gcc 4.7.2中的std::map实现效率非常低?,c++,linux,windows,gcc,c++11,C++,Linux,Windows,Gcc,C++11,有人能帮助我理解std::map容器是如何实现的吗?我有一个包含原子成员的类,并且我不需要调用复制构造函数,所以我使用c++11 delete操作符来抑制复制构造函数的隐式生成 MyCalss(const MyClass& a) = delete; 这在我的windows构建中运行良好,但是在Linux中,我遇到了一个错误,通知我std::map类的[]操作符正在尝试调用一个已删除的函数 map的Windows VS2013和Linux GCC 4.7.x实现之间似乎存在重大差异。这让

有人能帮助我理解std::map容器是如何实现的吗?我有一个包含原子成员的类,并且我不需要调用复制构造函数,所以我使用c++11 delete操作符来抑制复制构造函数的隐式生成

MyCalss(const MyClass& a) = delete;
这在我的windows构建中运行良好,但是在Linux中,我遇到了一个错误,通知我std::map类的[]操作符正在尝试调用一个已删除的函数

map的Windows VS2013和Linux GCC 4.7.x实现之间似乎存在重大差异。这让我做了一个关于如何将对象插入地图的实验

我编写了这个小示例程序:

#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();
}
这就是我在写作时希望看到的

 TestItemMap["foo"].doStuff();
我希望map会创建一个新的TestItem实例,然后通过将树节点内部链接到新的TestItem,将其插入到红黑树中

然而,当我在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真的是这样低效吗?
人们有没有一些标准的技巧来克服这个问题?

这似乎是GCC4.8修复的一个bug

  • 它适用于GCC4.8
  • 它无法使用GCC4.7进行编译

首先,我解决了那个可怕的
sprintf\u
问题:

string id() 
{
   static int id = 0;
   std::stringstream s;
   s << id++;
   return s.str();
}

MSVC似乎自动使用C++11特性(最有可能的是移动语义)来提高性能,而您需要明确告诉g++也这样做。

默认情况下,GCC使用的标准库是调用的,并且是开源的。还附带了GCC源代码。如果您想知道它是如何实现的,只需下载源代码并查看它。您正在比较启用优化的两种编译,不是吗?至于您的问题,我更好奇的是,有两行代码指出
TestItem0
已销毁。sprintf_不是标准的,因此它不能在linux上编译。您使用了什么代码?@JoachimPileborg,这是显然未经考虑的赋值运算符的结果,用于
TestItemMap[“new mooky key”]=a,我打赌OP没有看到它的出现。我敢说这不是一个GCC错误,但是MSVC没有正常工作。隐式声明的移动构造函数不会在用户声明的复制构造函数存在时生成。所以,GCC不能因为不能使用移动语义而受到指责——用户已经告诉它不要这样做。(不要问我为什么版本4.8“工作”,尽管如此)@Damon新元素是默认构建的,然后赋值,我实际上看不到元素在哪里/应该复制。错误,AFAICT,可能是GCC 4.7在实例化
操作符[]
时需要在内部复制可构造性,这是标准不要求/不允许的。@Damon我认为它可能是一个内部
节点
结构(或类似的东西)在正在进行移动构造的
std::map
内部,其效果是避免用户的复制构造函数。@TristanBrindle否,不需要复制或移动构造函数,节点应使用默认构造函数并在适当位置构造新元素。这就是VC和GCC4.8都在做的事情。然后,它们从
操作符[]
返回对该新元素的引用,并进行赋值,请参见我链接的示例。
string id() 
{
   static int id = 0;
   std::stringstream s;
   s << id++;
   return s.str();
}
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 TestItem0
Destroying TestItem1
Destroying TestItem0