C ++ 03 libstdc ++与C ++ 11中的伪造副本 [英] Spurious copies in c++03 libstdc++ vs 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
另外两个副本从哪里来?
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 keyk
,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, insertsvalue_type(x, T())
into the map.
(其中 x
是 operator [] $的参数c $ c>)
这篇关于C ++ 03 libstdc ++与C ++ 11中的伪造副本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!