C++ c++;将构造实例复制到映射中
下面是一段代码,其中包含一个简单的类Foo,该类被实例化,然后插入到映射中。 我不明白将foo插入fooMap时如何调用copy构造函数C++ c++;将构造实例复制到映射中,c++,map,copy-constructor,C++,Map,Copy Constructor,下面是一段代码,其中包含一个简单的类Foo,该类被实例化,然后插入到映射中。 我不明白将foo插入fooMap时如何调用copy构造函数 #include <stdlib.h> #include <stdio.h> #include <map> #include <iostream> using namespace std; class Foo { public: //default constructor
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <iostream>
using namespace std;
class Foo {
public:
//default constructor
Foo() {
name_ = string("Undefined") + suffix();
cout << "Constructing Foo '"<< name_ << "'" << endl;
};
//constructor with arg
Foo(const char* name): name_(name) {
cout << "Constructing Foo '" << name << "'" << endl;
};
//default const copy-constructor
Foo(const Foo &foo) {
name_ = foo.get_name() + suffix();
cout << "Copying const Foo '" << foo.get_name() << "' into Foo '" << name_ << "'" << endl;
}
//default destructor
~Foo() {
cout << "Destroying Foo '" << name_ << "'" << endl;
}
//getting name
const string get_name() const {
return name_;
};
//setting name
void set_name(string new_name){
name_ = new_name;
}
//suffix for name
string suffix() {
static int cmp=0;
char ch[2];
sprintf(ch,"%d",cmp++);
return string(ch);
}
private:
string name_;
};
int main() {
typedef map<string, Foo> FooMapType;
FooMapType fooMap;
cout << "1:\n";
Foo foo("bar");
cout << "\n2:\n";
fooMap["bar"] = foo;
cout << "\n3:\n";
cout << fooMap["bar"].get_name() << endl;
foo.set_name("baz");
cout << "\n4:\n";
但我希望调用foo copy构造函数,导致输出:
Copying const Foo 'bar' into Foo 'Undefined0'
你在做作业,而不是复制行
fooMap[“bar”]=foo中的构造
OverrideFoo&operator=(const-Foo&)
以查看这种情况
默认的构造是创建您将分配到的初始项
您看到的副本可能是映射实现的内部副本—将其放在树中的适当位置。比我预期的要多。你在做作业,而不是复制行中的结构
fooMap[“bar”]=foo
OverrideFoo&operator=(const-Foo&)
以查看这种情况
默认的构造是创建您将分配到的初始项
您看到的副本可能是映射实现的内部副本—将其放在树中的适当位置。这比我预料的要多。一个好问题,我也有同样的行为。STL实现的细节创建默认对象,然后使用另一种方法复制数据
退一步说,我们可以看到,一旦调用了insert(或者在您的例子中是运算符[])方法,地图中确实存在原始对象的副本,这很可能就是标准承诺的所有内容。一个好问题,我得到了相同的行为。STL实现的细节创建默认对象,然后使用另一种方法复制数据 退一步说,我们可以看到,一旦调用了insert(或者在您的例子中是运算符[])方法,映射中确实存在原始对象的副本,这很可能就是标准承诺的全部内容。
fooMap[“bar”]=foo
将生成默认构造、两个副本和一个赋值
默认结构是必需的,因为键“bar”
没有字符串foo对
第一个副本是由键“bar”
和从刚刚创建的默认构造的foo
复制的值构成的
第二次复制是将这对复制到地图中
然后赋值将映射中的值赋值给foo
在C++11中使用R值语义的STL实现可以使其更加高效。fooMap[“bar”]=foo
生成一个默认构造、两个副本和一个赋值
默认结构是必需的,因为键“bar”
没有字符串foo对
第一个副本是由键“bar”
和从刚刚创建的默认构造的foo
复制的值构成的
第二次复制是将这对复制到地图中
然后赋值将映射中的值赋值给foo
在C++11中使用R值语义的STL实现可以使这一点更加有效。
map::operator[]
返回对值成员的引用,因此下面的语句:
fooMap["bar"] = foo;
可以解释为:
Foo& fooRef = fooMap["bar"]; // (1)
fooRef = foo; // (2)
在(1)map::operator[]
中执行,在(2)Foo::operator=
中执行
如果给定的键在映射中不存在,map::operator[]
将创建一个新元素—由提供的键和使用默认构造函数构造的值对象组成的一对。(在您的示例中,键类型是std::string
,值类型是Foo
)。如果给定的键存在,它只返回对value对象的引用
第(2)行通过其引用更改值
如果您看一下map::operator[]
(我在这里提供了Microsoft的一个,来自VS2010附带的STL库),您可以看到它调用map::insert()
在发动机罩下,为其提供临时对象值\u类型
,该临时对象再次由临时对象映射的\u类型
创建:
mapped_type& operator[](const key_type& _Keyval)
{
// find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end() || this->comp(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where, value_type(_Keyval, mapped_type()));
return ((*_Where).second);
}
value\u-type
基本上是我上面提到的配对,在您的案例中mapped\u-type
是Foo
。
mapped_type()
通过调用其默认构造函数来创建临时对象。这与输出中的第二个默认构造函数相匹配(在创建局部变量foo
时调用第一个构造函数)value\u type
的构造函数使用mapped\u type
的复制构造函数来创建其value成员的实例。这与Foo
的复制构造函数的第一个调用相匹配。在您的日志中还有另一个对此构造函数的调用,为了找到它的源代码,我们需要深入挖掘map::operator[]
…实际上是它调用的insert
方法:
template<class _Valty>
typename _STD tr1::enable_if<!_STD tr1::is_same<const_iterator, typename _STD tr1::remove_reference<_Valty>::type>::value, iterator>::type
insert(const_iterator _Where, _Valty&& _Val)
{
// try to insert node with value _Val using _Where as a hint
return (_Insert(_Where, this->_Buynode(_STD forward<_Valty>(_Val))));
}
树节点封装了pair对象映射的元素,因此它的创建涉及到创建pair的另一个副本-\u Val
,这是另一个调用Foo
的副本构造函数的地方
map::operator[]
call创建了两个包含Foo
的临时对象,返回时这些对象被销毁,因此您可以在输出中看到两个析构函数调用
如果实现Foo::operator=
并在其中放置跟踪,您将能够看到该方法也被调用(第(2)行)
如果以后将同一个键映射到其他某个Foo
对象,则只能执行Foo::operator=
,因为该键的映射元素已经创建,并且只有值通过其引用被更改。map::operator[]
返回对值成员的引用,因此以下语句:
fooMap["bar"] = foo;
可以解释为:
Foo& fooRef = fooMap["bar"]; // (1)
fooRef = foo; // (2)
在(1)map::operato