Linux vs Windows std::map 赋值构造函数(为什么会有这样的区别?)

Linux vs Windows std::map assignment constructors (Why such a difference?)

本文关键字:区别 std Windows vs map 赋值 Linux 构造函数 为什么      更新时间:2023-10-16

我在用Linux Ubuntu编写的C++应用程序中目睹了一些意外的行为。我会用参数构造一个对象,然后使用赋值运算符将该对象的副本放入 std::map 中。我写了一个简单的程序来演示这种情况......

#include <iostream>
#include <string>
#include <map>
using namespace std;
class Foo
{
public:
   Foo(void) : _x(0)
   {
      cout << "Default" << endl;
   }
   Foo(int a) : _x(a)
   {
      cout << "Param" << endl;
   }
   Foo(Foo const &foo) :
      _x(foo._x)
   {
      cout << "Copy" << endl;
   }
   Foo& operator=(Foo const &foo)
   {
      cout << "Assignment" << endl;
      if (this != &foo)
      {
         _x = foo._x;
      }
      return *this;
   }
   int get(void)
   {
      return _x;
   }
private:
   int _x;
};
int main(int argc, char *argv [])
{
   std::map<int, Foo> foos;
   Foo a_foo(10);
   foos[100] = a_foo;
   return 0;
}

在这里,我只是打印出哪个构造函数/运算符以什么顺序被调用,这样我可以看到构造和赋值在"main"函数中是如何工作的。

当我在 Windows 中运行它时,我得到了预期的输出......

参数
违约
分配

当我在 Linux 中运行它时,我得到以下输出...

参数
违约
复制
复制
分配

为什么有两个额外的复制构造函数?创建这么多次对象似乎效率很低?

谢谢!

答案就在stl_map.h。它的行为取决于您是否使用 C++11 支持进行编译。 如果这样做,则 STL 可以利用移动语义来避免不必要的复制。VC++ 默认使用新的语言功能,但如果使用 g++ 或 clang,则需要习惯在 4.2 中使用 -std=c++0x 标志,或者在较新版本中使用 -std=c++11 标志。

设置-std=c++11后,使用 g++4.8 的输出为:

Param
Default
Assignment

编辑:非常感谢您为我澄清,我假设这是移动语义是不正确的。我把这个答案留在原地,以引导用户找到这个更好的答案。