为什么复制构造函数被调用25次,而插入循环只迭代10次?

时间:2017-09-21 09:59:11

标签: c++ vector copy-constructor

我想知道为什么在以下C ++代码中,复制构造函数被调用25次10次迭代?

如果是10,那么确定10/10 = 120/10 = 230/10 = 3,但是25/10 = 2.5?这里.5是什么意思?

标题

class Person
{
public:
    Person(std::string name, int age);
    Person(const Person &person);

    const std::string &getName() const;
    int getAge() const;

private:
    std::string name;
    int age;
};

来源:

Person::Person(string name, int age) : name(std::move(name)), age(age)
{}

Person::Person(const Person &person)
{
    this->name = person.name;
    this->age = person.age;
    static int count = 0;
    count++;
    cout << ">>Copy-Person::Person(Person &person) " << count << endl;
}

const string &Person::getName() const
{
    return name;
}

int Person::getAge() const
{
    return age;
}

用法:

int main()
{
    vector<Person> persons;

    for (int i = 0; i < 10; ++i)
    {
        Person person(to_string(i + 1), i);
        persons.push_back(person);
    }
    cout << "-----------------------------------------------" << endl;
    for (Person &person : persons)
    {
        cout << "name = " << person.getName() << " age = " << person.getAge() << endl;
    }
    return 0;
}

输出:

>>Copy-Person::Person(Person &person) 1
>>Copy-Person::Person(Person &person) 2
>>Copy-Person::Person(Person &person) 3
>>Copy-Person::Person(Person &person) 4
>>Copy-Person::Person(Person &person) 5
>>Copy-Person::Person(Person &person) 6
>>Copy-Person::Person(Person &person) 7
>>Copy-Person::Person(Person &person) 8
>>Copy-Person::Person(Person &person) 9
>>Copy-Person::Person(Person &person) 10
>>Copy-Person::Person(Person &person) 11
>>Copy-Person::Person(Person &person) 12
>>Copy-Person::Person(Person &person) 13
>>Copy-Person::Person(Person &person) 14
>>Copy-Person::Person(Person &person) 15
>>Copy-Person::Person(Person &person) 16
>>Copy-Person::Person(Person &person) 17
>>Copy-Person::Person(Person &person) 18
>>Copy-Person::Person(Person &person) 19
>>Copy-Person::Person(Person &person) 20
>>Copy-Person::Person(Person &person) 21
>>Copy-Person::Person(Person &person) 22
>>Copy-Person::Person(Person &person) 23
>>Copy-Person::Person(Person &person) 24
>>Copy-Person::Person(Person &person) 25
-----------------------------------------------
name = 1 age = 0
name = 2 age = 1
name = 3 age = 2
name = 4 age = 3
name = 5 age = 4
name = 6 age = 5
name = 7 age = 6
name = 8 age = 7
name = 9 age = 8
name = 10 age = 9

3 个答案:

答案 0 :(得分:4)

您没有为persons向量保留任何内存。这意味着在persons.size() == persons.capacity()期间{@ 1}}时,向量将在堆上分配一个新的更大的缓冲区并将每个元素复制到它。这就是为什么你会看到比预期更多的副本。

如果你写......

push_back

...在循环之前,您将看不到任何“额外”副本。

live example on wandbox

请注意,您可以同时使用persons.reserve(10); std::vector::emplace_back来避免复制altogheter:

std::vector::reserve

这只会打印:

  

name = 1 age = 0

     

name = 2 age = 1

     

name = 3 age = 2

     

name = 4 age = 3

     

name = 5 age = 4

     

name = 6 age = 5

     

name = 7 age = 6

     

name = 8 age = 7

     

name = 9 age = 8

     

name = 10 age = 9

live example on wandbox

答案 1 :(得分:2)

新的size()&gt; capacity()的{​​{1}},重新分配发生。所有元素都将被复制到新的内部存储中,然后将在当前元素中调用复制构造函数。次数。有关如何增加容量的详细信息取决于实现,似乎您使用的实现只是每次重新分配的容量的两倍。所以

vector

这就是你得到25次结果的原因。

正如@VittorioRomeo解释的那样,您可以使用std::vector::reserve来避免重新分配。

答案 2 :(得分:2)

std::vector::size()到达std::vector::capacity()时,std::vector将为更多对象腾出空间,分配更大容量的更大缓冲区,并复制< / em>先前存储的对象进入新缓冲区 这会触发Person类的新复制构造函数调用(我尝试使用VS2015编写代码,并且我有35个复制构造函数调用)。

请注意,如果您使用std::vector方法在reserve()中保留足够的空间,则可以获得10个复制构造函数调用:

vector<Person> persons;

// Reserve room in the vector to store 10 persons
persons.reserve(10);

for (int i = 0; i < 10; ++i)
{
    Person person(to_string(i + 1), i);
    persons.push_back(person);
}

这是因为,在这种情况下,你在向量中留出了足够的空间,因此向量的大小不会超过其容量(因此,不需要分配新的更大的缓冲区,并将旧数据复制到这个新的缓冲区)。

所有这一切,如果您的Person课程可移动构建std::vector移动之前创建的Person对象而不是复制它们,这更快。

如果您在Person课程中添加此行:

class Person 
{
  public:
   ...

   // Synthesize default move constructor
   Person(Person&&) = default;
   ...
};

即使您没有调用vector::reserve()方法,也可以获得10个复制构造函数调用。