tah*_*ith 6 c++ 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;
}
Run Code Online (Sandbox Code Playgroud)
使用-std = c ++ 11在gcc中编译并获得输出,
Param
Default
Assignment
Run Code Online (Sandbox Code Playgroud)
删除-std = c ++ 11,然后你得到,
Param
Default
Copy
Copy
Assignment
Run Code Online (Sandbox Code Playgroud)
这两份额外的副本来自哪里?
它们与调用下标运算符有关,而与调用无关.(如果删除了作业,它们仍然存在.)对于我来说,即使在C++之前的11世界中,它们也似乎并不需要,正如libc ++示例所示.
这最初的动机是看这个问题
这是LWG 334:
C++ 03 Standard要求operator[]([lib.map.access] p1)具有以下效果:
返回:
(*((insert(make_pair(x, T()))).first)).second.
libstdc ++实现了operator[]在C++ 03模式下使用的插入(在密钥不存在的情况下),如下所示:
__i = insert(__i, value_type(__k, mapped_type()));
Run Code Online (Sandbox Code Playgroud)
__i 是插入点,它被计算为
iterator __i = lower_bound(__k);
Run Code Online (Sandbox Code Playgroud)
__k是参数operator[].
临时的创建value_type(__k, mapped_type())导致第一副本(从mapped_type()进入value_type对).第二个副本是结果insert,它将该value_type对复制到实际节点中.
1997年的原始版本是:
return (*((insert(value_type(k, T()))).first)).second;
Run Code Online (Sandbox Code Playgroud)
这几乎是标准的字母(当时甚至不存在!).它最后一次改变是在1998年.在此之前,它使用了:
__i = insert(__i, value_type(__k, _Tp()));
Run Code Online (Sandbox Code Playgroud)
提交消息说这是
更新到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的建议解决方案:
效果:如果
x地图中没有等效的键,则插入value_type(x, T())到地图中.
(x参数在哪里operator[])