C++ c++;将构造实例复制到映射中

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

下面是一段代码,其中包含一个简单的类Foo,该类被实例化,然后插入到映射中。 我不明白将foo插入fooMap时如何调用copy构造函数

#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中的构造
Override
Foo&operator=(const-Foo&)
以查看这种情况

默认的构造是创建您将分配到的初始项


您看到的副本可能是映射实现的内部副本—将其放在树中的适当位置。比我预期的要多。

你在做作业,而不是复制行中的结构
fooMap[“bar”]=foo
Override
Foo&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