C ++ 03 libstdc ++与C ++ 11中的伪造副本 [英] Spurious copies in c++03 libstdc++ vs c++11

查看:92
本文介绍了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中进行编译,您可以得到输出,

Compiled in gcc with -std=c++11 and you get the output,

Param
Default
Assignment

删除-std = c ++ 11,则得到

Remove -std=c++11, then you get,

Param
Default
Copy
Copy
Assignment

with c ++ 11

没有

libc ++示例在c ++ 03模式下产生上乘输出

另外两个副本从哪里来?

Where are the two extra copies coming from?

它们与调用下标运算符有关,与赋值无关。 (如果删除任务,它们仍然存在。)对我来说,即使在C ++ 11之前的版本中,libc ++示例也是如此,它们似乎并不是必需的。

They are related to calling the subscript operator, not the assignment. (They remain if you remove the assignment.) To me they don't seem to be needed, even in a pre-C++11 world, as the libc++ example shows.

这最初是通过查看这个问题

推荐答案

这是 LWG 334

C ++ 03 Standard对 operator [] ([lib.map.access] p1)强制要求以下效果:

The C++03 Standard mandates the following effects for operator[] ([lib.map.access]p1):


返回值: (*(((插入(make_pair(x,T())))。first))。second






libstdc ++实现了运算符[]所使用的插入。 (在键尚不存在的情况下)在C ++ 03模式下如下:


libstdc++ implements the insertion used by operator[] (in the case where the key doesn't exist yet) as follows in C++03 mode:

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

__ i 是插入点,它是计算为

__i is the insertion point, it is computed as

iterator __i = lower_bound(__k);

__ k operator []

创建临时 value_type(__ k,mapping_type())导致第一个副本(从 mapped_type() value_type 对)。第二个副本是 insert 的结果,该副本将 value_type 对复制到实际节点中。

The creation of the temporary value_type(__k, mapped_type()) causes the first copy (from mapped_type() into the value_type pair). The second copy is the result of insert, which copies the value_type pair into an actual node.

1997年的原始版本是:

The original version from 1997 is:

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

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

which is almost to the letter of the Standard (which didn't even exist back then!). The last time it was changed significantly was in 1998. Prior to that, it used:

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

提交消息说这是为了


更新到SGI STL 3.11。

Update to SGI STL 3.11.






早期版本的SGI STL(1995)确实指定了 map ::运算符[] 的方式与C ++ 03 Standard相同:


Earlier versions of the SGI STL (1995) did indeed specify map::operator[] in the same way as the C++03 Standard:


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

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(.. 仍然在libstdc ++中使用 lower_bound 存在,并且仅在密钥尚不存在时才创建配对。

SGI STL v2.03 (1997) had already switched to using value_type instead of make_pair. And as gcc's commit log suggests, SGI STL's implementation changed again between v3.0 (also 1997) and v3.11 (1998) from insert(value_type(.. to the form still present in libstdc++ using lower_bound and only creating the pair if the key doesn't exist yet.

所以可以说libstdc ++实现了LWG 334( value_type 而不是 make_pair )。这并不是发生的事情,只是查看其历史。它只是遵循 SGI STL 。libc ++在这方面并不严格符合C ++ 03。

So one could say that libstdc++ implements the first proposed resolution of LWG 334 (value_type instead of make_pair). This isn't exactly what happened, though, looking at its history. It's simply following SGI STL. libc++ doesn't strictly conform to C++03 in this respect.

libstdc ++的同一运算符的C ++ 11版本使用了自定义放置功能。C ++ 11标准的 map :: operator [] 规范遵循LWG的建议分辨率。 334:

libstdc++'s C++11 version of the same operator uses a custom emplacement function. The C++11 Standard's specification of map::operator[] follows the proposed resolution of LWG 334:


效果:如果没有等效的键到地图中的 x ,将 value_type(x,T())插入地图。

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

(其中 x operator []

这篇关于C ++ 03 libstdc ++与C ++ 11中的伪造副本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆