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

前端之家收集整理的这篇文章主要介绍了c 03 libstdc与c 11中的虚假副本前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
考虑以下代码
#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

with c++11

without

libc++ example producing the superior output in c++03 mode

这两份额外的副本来自哪里?

它们与调用下标运算符有关,而与调用无关. (如果你删除了作业,它们仍然存在.)对我来说,他们似乎并不需要,即使在前C11世界中,正如libc示例所示.

这最初的动机是看this question

解决方法

这是 LWG 334

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

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

libstdc在C03模式下实现operator []使用的插入(在密钥不存在的情况下),如下所示:

__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,_Tp()));

提交消息说这是

Update to SGI STL 3.11.

Earlier versions of the SGI STL (1995)确实以与C 03标准相同的方式指定了map :: operator []:

For a map m and key k,m[k] is semantically equivalent to (*((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(..到使用lower_bound的libstdc中仍存在的形式)再次改变,如果密钥尚不存在.

所以可以说libstdc实现了LWG 334的第一个提议解决方案(value_type而不是make_pair).然而,这并不是发生的事情,看着它的历史.它只是遵循SGI STL.在这方面,libc并不严格遵守C 03.

libstdc的同一运算符的C 11版本使用自定义安置功能. C 11标准的map :: operator []规范遵循LWG 334的建议解决方案:

Effects: If there is no key equivalent to x in the map,inserts value_type(x,T()) into the map.

(其中x是operator []的参数)

猜你在找的C&C++相关文章