首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么复制构造函数被调用25次,而插入循环只迭代10次?

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

Stack Overflow用户
提问于 2017-09-21 09:59:11
回答 3查看 300关注 0票数 6

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

如果是10,那么OK 10/10 = 1,或者20/10 = 2,或者30/10 = 3,但是25/10 = 2.5?这里的.5是什么意思?

头:

代码语言:javascript
运行
复制
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;
};

资料来源:

代码语言:javascript
运行
复制
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;
}

使用:

代码语言:javascript
运行
复制
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;
}

输出:

代码语言:javascript
运行
复制
>>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
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-09-21 10:02:02

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

如果你写..。

代码语言:javascript
运行
复制
persons.reserve(10); 

...before循环,您将不会看到任何“额外”副本。

魔盒活生生的例子

请注意,您可以同时使用std::vector::emplace_backstd::vector::reserve来避免复制

代码语言:javascript
运行
复制
for (int i = 0; i < 10; ++i)
{
    persons.emplace_back(to_string(i + 1), i);
}

这只会打印:

姓名=1岁=0 姓名=2岁=1 姓名=3岁=2 姓名=4岁=3岁 姓名=5岁=4岁 姓名=6岁=5岁 姓名=7岁=6岁 姓名=8岁=7岁 姓名=9岁=8岁 姓名= 10岁=9岁

魔盒活生生的例子

票数 4
EN

Stack Overflow用户

发布于 2017-09-21 10:14:25

当新的size() > capacity()vector时,就会发生重新分配。所有元素都将复制到新的内部存储中,然后在当前元素的次数中调用复制构造函数。关于如何增加容量的细节取决于实现,您使用的实现似乎是每次重新分配所使用的能力的两倍。所以

代码语言:javascript
运行
复制
#iterator current size  capacity  times of the copy (for reallocatioin + for push_back)
1         0             0         0 + 1             
2         1             1         1 + 1             
3         2             2         2 + 1             
4         3             4         0 + 1             
5         4             4         4 + 1             
6         5             8         0 + 1             
7         6             8         0 + 1             
8         7             8         0 + 1             
9         8             8         8 + 1             
10        9             16        0 + 1             

所以你才得到了25次的结果。

正如@VittorioRomeo解释的那样,您可以使用std::载体::储备金来避免重新分配。

票数 2
EN

Stack Overflow用户

发布于 2017-09-21 10:16:57

std::vector::size()到达std::vector::capacity()时,std::vector将为更多的对象腾出空间,分配一个容量更大的新缓冲区,并将先前存储的对象复制到新缓冲区中。

这将为您的Person类触发新的复制构造函数调用(我用VS2015尝试了您的代码,并得到了35个复制构造函数调用)。

注意,如果您在std::vector中使用reserve()方法预留了足够的空间,那么您将得到精确的10个复制构造函数调用:

代码语言:javascript
运行
复制
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);
}

这是因为,在本例中,您在向量中腾出了足够的空间,因此向量的大小不超过其容量(因此,不需要分配一个新的更大的缓冲区,并将旧数据复制到这个新缓冲区)。

尽管如此,如果您的move-constructible,类是Person,那么std::vector将移动以前创建的Person对象,而不是复制它们,这样会更快。

如果在Person类中添加这一行:

代码语言:javascript
运行
复制
class Person 
{
  public:
   ...

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

即使不调用vector::reserve()方法,也会得到整整10个复制构造函数调用。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46340962

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档