2015-05-20 2 views
2

У меня есть ребенок класса, и простой вектор оттеснить реализации, как это:почему-копия конструктор вызывается дважды при выполнении vector.push_back

#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 появляется только один раз. Почему дважды создается копия-конструктор?

+7

_Questions, ищущий помощь для отладки («почему этот код не работает?») должен включают в себя желаемое поведение, конкретную проблему или ошибку и кратчайший код, необходимый для воспроизведения его в самом вопросе. Вопросы без четкого описания проблемы не полезны для других читателей. См.: [Как создать минимальный, полный и проверенный пример ] (http://stackoverflow.com/help/mcve). По крайней мере покажите свое объявление класса 'Child'. –

+0

У нас, по крайней мере, отсутствует определение' Child'. – Shoe

+2

Я создал тестовый проект, и я не вижу поведения, которое вы предлагаете. Он просто создает и копирует один. http://coliru.stacked-crooked.com/a/5460f09cdc665fd8 –

ответ

1

Официальный ответ: В случае вашего класса std :: vector может делать столько копий, сколько им нравится, поскольку в стандарте нет ограничений.

Что, вероятно, происходит: копия выполняется при передаче объекта в качестве параметра и снова, когда вектор изменяется внутри.

Разве это неэффективно? Да

Как его улучшить?

Либо удалите пользовательский деструктор и конструктор копирования, либо определите собственный конструктор перемещения и оператор копирования. Первый случай позволяет компилятору создавать свои собственные операции перемещения, которые они предоставляют.

После того, как компилятор может сделать вывод, что ваш класс въезда известно, операции StD :: вектор становится намного более эффективными, и вы увидите ровно один экземпляр (потому что вы заставляете компилятор сделать один называя Child называется Item1)

Edit: рассмотрим пример

#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; 
} 

пример вывода:

constructing child 
copy-constructing child 
destructing child 
destructing child 

constructing child 
move-constructing child 
destructing zombie 
destructing child 

constructing child 
move-constructing child 
destructing zombie 
destructing child 
+1

'push_back' требуется для принятия' const & 'и' && ', поэтому там не должно быть копии. –

+0

@BillyIneal есть копия, потому что Item1 не' std :: move'd. –

+2

Передача 'const &' не приводит к копированию. –

1

Thi s происходит потому, что вы используете старый компилятор. Извините, если это не очень захватывающий вывод. :-(Никто другой не может реплицировать проблему даже на новых компиляторах Microsoft. Хотя Ричард Ходжес прав, когда говорит, что компилятор может делать копии по своему усмотрению, современные компиляторы делают все возможное, чтобы их избежать. в случае, когда вы указываете, достойный компилятор не должен делать копию, и если вас беспокоит производительность, вы должны рассмотреть возможность перехода на более новую версию.

Смежные вопросы