jjzjj

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

coder 2024-06-08 原文

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

MyCalss(const MyClass& a) = delete;

这在我的 Windows 构建中运行良好,但是在 Linux 中,我收到一条错误消息,通知我 std::map 类的 [] 运算符正在尝试调用已删除的函数。

在 Windows VS2013 和 Linux GCC 4.7.x map 实现之间似乎存在重大差异。这促使我做了一个关于如何将对象插入 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();

我希望 map 会创建一个新的 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 真的这么低效吗?

人们是否有一些标准技巧可以用来克服这个问题?

最佳答案

首先,我修复了那个可怕的 sprintf_s 问题:

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

并且还更改了您的“查找已经插入的值”以实际执行它所说的[编辑:您也是:-)]

现在,在 C++03 模式下使用 g++ 4.8.1 进行编译,我得到了与您类似的结果。但是用 -std=c++11 编译,我得到了

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

似乎 MSVC 自动使用 C++11 功能(最有可能是移动语义)来提供不错的性能提升,而您需要明确告诉 g++ 做同样的事情。

关于c++ - 与 VS2013 相比,gcc 4.7.2 中的 std::map 实现效率非常低?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19765827/

有关c++ - 与 VS2013 相比,gcc 4.7.2 中的 std::map 实现效率非常低?的更多相关文章

  1. ruby-on-rails - Railstutorial : db:populate vs. 工厂女孩 - 2

    在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby-on-rails - 无法在centos上安装therubyracer(V8和GCC出错) - 2

    我正在尝试在我的centos服务器上安装therubyracer,但遇到了麻烦。$geminstalltherubyracerBuildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingtherubyracer:ERROR:Failedtobuildgemnativeextension./usr/local/rvm/rubies/ruby-1.9.3-p125/bin/rubyextconf.rbcheckingformain()in-lpthread...yescheckingforv8.h...no***e

  4. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  5. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  6. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  7. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  8. Ruby#index 方法 VS 二进制搜索 - 2

    给定一个元素和一个数组,Ruby#index方法返回元素在数组中的位置。我使用二进制搜索实现了我自己的索引方法,期望我的方法会优于内置方法。令我惊讶的是,内置的在实验中的运行速度大约是我的三倍。有Rubyist知道原因吗? 最佳答案 内置#indexisnotabinarysearch,这只是一个简单的迭代搜索。但是,它是用C而不是Ruby实现的,因此自然可以快几个数量级。 关于Ruby#index方法VS二进制搜索,我们在StackOverflow上找到一个类似的问题:

  9. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  10. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

随机推荐