c++03 libstdc++ 与 c++11 中的虚假副本

2023-11-27

考虑这段代码:

#include <iostream>
#include <string>
#include <map>

using namespace std;

class Foo
{
public:
   Foo() : _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;
      _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;
}

使用 -std=c++11 在 gcc 中编译,得到输出,

Param
Default
Assignment

删除 -std=c++11,然后你得到,

Param
Default
Copy
Copy
Assignment

使用c++11

without

libc++ 示例在 c++03 模式下产生出色的输出

额外的两份副本从哪里来?

它们与调用下标运算符有关,而不是与赋值有关。 (如果删除赋值,它们仍然存在。)对我来说,即使在 C++11 之前的世界中,它们似乎也不需要,如 libc++ 示例所示。

这最初是出于查看这个问题


This is LWG 334:

C++03 标准要求以下效果:operator[]([lib.map.access]p1):

Returns: (*((insert(make_pair(x, T()))).first)).second.


libstdc++ 实现了使用的插入operator[](在key还不存在的情况下)在C++03模式下如下:

 __i = insert(__i, value_type(__k, mapped_type()));

__i是插入点,计算公式为

iterator __i = lower_bound(__k);

__k是参数operator[].

临时的创建value_type(__k, mapped_type())导致第一个副本(来自mapped_type()进入value_type一对)。第二个副本的结果是insert,它复制了value_type配对成实际节点。

1997 年的原始版本是:

return (*((insert(value_type(k, T()))).first)).second;

这几乎符合标准的字面意思(当时甚至不存在!)。上次对其进行重大更改是在 1998 年。在此之前,它使用:

__i = insert(__i, value_type(__k, _Tp()));

提交消息说这是为了

更新至 SGI STL 3.11。


SGI STL 的早期版本 (1995)确实指定了map::operator[]与 C++03 标准相同:

对于地图m和钥匙k, m[k]在语义上等价于(*((m.insert(make_pair(k, T()))).first)).second .

SGI STL v2.03 (1997) 已经改用value_type代替make_pair。正如 gcc 的提交日志所表明的那样,SGI STL 的实现在 v3.0(也是 1997 年)和 v3.11(1998 年)之间再次发生了变化insert(value_type(..使用 libstdc++ 中仍然存在的形式lower_bound并且仅在密钥尚不存在时才创建该对。


所以可以说 libstdc++ 实现了 LWG 334 的第一个提议的决议(value_type代替make_pair)。然而,纵观其历史,事实并非如此。它只是以下SGI STL。 libc++ 在这方面并不严格符合 C++03。


libstdc++ 的 C++11 版本的同一运算符使用自定义定位函数。 C++11 标准的规范map::operator[]遵循 LWG 334 的拟议决议:

Effects:如果没有相当于的键x在地图中,插入value_type(x, T())进入地图。

(where x是参数operator[])

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++03 libstdc++ 与 c++11 中的虚假副本 的相关文章

随机推荐