为什么在执行vector.push_back时调用copy-constructor两次

时间:2015-05-20 19:14:26

标签: c++ stl

我有一个Class Child,以及一个简单的向量推送实现,如下所示:

#include <stdio.h>
#include <vector>
#include <iostream>

class Child 
{
    public:
        Child();
        Child(const Child &item);
        ~Child();
};

Child::Child()
{
    std::cout<<"Constructing Child\n";
}

Child::Child(const Child &item)
{
    std::cout<<"Copy-Constructing Child\n";
}

Child::~Child()
{
    std::cout<<"Destructing Child\n";
}

int main()
{
    std::vector<Child> v;
    Child Item1;
    v.push_back(Item1);
}

在调用v.push_back( Item1 );之后,我有以下输出:

Constructing Child
Copy-Constructing Child
Copy-Constructing Child
Destructing Child

我原以为Copy-Constructing Child只会出现一次。为什么复制构造函数被调用两次?

2 个答案:

答案 0 :(得分:1)

官方回答:对于你的班级,std :: vector可以随意制作任意数量的副本,因为标准中没有规定限制。

可能发生的事情:在将对象作为参数传递时进行复制,并在内部调整向量时再次进行复制。

效率不高吗?是

我该如何改进?

删除自定义析构函数和复制构造函数,或者定义自定义移动构造函数和复制运算符。前一种情况允许编译器创建自己的移动操作,后者提供它们。

一旦编译器推断出你的类是移动感知的,std :: vector的操作就会变得更有效率,你会看到一个副本(因为你强迫编译器通过命名{{1}来创建一个副本) } Child}

编辑:考虑这个例子

Item1

示例输出:

#include <stdio.h>
#include <vector>
#include <iostream>

class Child
{
public:
    Child();
    Child(const Child &item);
    Child(Child&& item);
    Child& operator=(const Child &item);
    Child& operator=(Child&& item);
    ~Child();

private:
    std::string name() const {
        return std::string { _zombie ? "zombie" : "child" };
    }
    bool _zombie = false;
};

Child::Child()
{
    std::cout << "constructing " << name() << "\n";
}

Child::Child(const Child &item)
{
    std::cout << "copy-constructing " << name() << "\n";
}

Child::Child(Child &&item)
{
    std::cout << "move-constructing " << name() << "\n";
    item._zombie = true;
}

Child& Child::operator=(const Child &item)
{
    _zombie = false;
    std::cout << "assigning " << name() << "\n";
    return *this;
}

Child& Child::operator=(Child &&item)
{
    item._zombie = true;
    _zombie = false;
    std::cout << "move-assigning " << name() << "\n";
    return *this;
}

Child::~Child()
{
    std::cout << "destructing " << name() << "\n";
}

using namespace std;

int main(int argc, const char * argv[])
{
    {
        std::vector<Child> v;
        Child item1;
        v.push_back(item1);
    }
    cout << endl;

    {
        std::vector<Child> v;
        v.push_back(Child{});
    }
    cout << endl;

    {
        std::vector<Child> v;
        Child item1;
        v.push_back(std::move(item1));
    }
    cout << endl;
    return 0;
}

答案 1 :(得分:1)

这种情况正在发生,因为您使用的是旧编译器。对不起,如果这不是一个非常令人兴奋的结论。 :-(没有其他人可以复制这个问题,即使在较新的微软编译器上也是如此。虽然理查德·霍奇斯认为编译器可以按照自己认为合适的方式自由复制,但现代编译器会尽力避免使用它们。你列出的情况,一个体面的编译器不应该复制,如果你担心性能,你应该考虑升级到更新的版本。