2015-10-09 4 views
2

Я изучаю, чтобы понять конструктор классов и деструктор. Я написал небольшой код консоли, чтобы добавить один экземпляр класса в вектор. Все хорошо и денди, но я не понимаю, что добавление одного объекта в вектор триггеров деструктора в два раза. Почему это происходит?Вектор и поведение push_back()

Если я не добавляю никакого объекта, вектор не вызывает конструктор или деструктор сам по себе, так почему это происходит дважды?

Может ли кто-нибудь объяснить, почему это происходит?

#include <cstdio> 
#include <vector> 
class Test 
{ 
    private: 
     int value; 

    public: 
     Test() 
     { 
      printf("\nClass constructor triggered."); 
     }; 
     ~Test() 
     { 
      printf("\nClass desctructor triggered."); 
     } 
}; 

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test()); 
    return 0; 
} 

UPDATE: Я добавил еще немного информации к классу так, что я получаю более конкретный вывод, однако теперь я заметил, что с каждым дополнением к вектору шаг-строительство и деструкторы вызовы увеличиваются. Является ли количество этих вызовов привязанным к количеству объектов внутри вектора или того, что происходит? У меня есть утечка? Извините, если слишком глупые вопросы. Ниже добавлен код:

#include <cstdio> 
#include <vector> 

class Test 
{ 
    private: 
     int value; 

    public: 
     // Constructor 
     Test(int v=0) 
     { 
      value = v; 
      printf("\n\n%i", value); 
      printf("\nClass constructor triggered."); 
     }; 

     // Copy-move constructor 
     Test(Test&&) 
     { 
      printf("\nClass move-constructor triggered."); 
     }; 

     // Destructor 
     ~Test() 
     { 
      value = 0; 
      printf("\nClass desctructor triggered."); 
     } 
}; 

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test(1)); 
    container.push_back(Test(2)); 
    container.push_back(Test(3)); 
    container.push_back(Test(4)); 

    printf("\n\nPushback complete!"); 
    return 0; 
} 
+0

Поскольку копия взята с помощью 'push_back()'. –

+0

Поскольку вектор содержит объекты, а не указатели на них, ваш объект будет скопирован на вставке, а затем уничтожаются два объекта. –

+2

@ πάνταῥεῖ: Ответы идут туда ↓↓↓↓↓ сколько раз я должен вам сказать –

ответ

3

Поскольку вы не печатаете каждый вызов конструктора, вы пропускаете вызов move-constructor. Ваш класс, помимо предоставленного вами конструктора по умолчанию, также неявно создал конструкторы перемещения и копирования.

Вектор сохраняет значение, и это значение должно быть каким-то образом инициализировано. Как правило, это происходит либо с помощью c-tor перемещения, либо с помощью скопированного c-tor, даже если объект также может быть создан непосредственно внутри вектора, используя, например, emplace_back.

Попробуйте добавить это:

Test(Test&&) 
{ 
    printf("\nClass move constructor triggered."); 
}; 

к классу, он должен изменить выход к чему-то, что имеет больше смысла (я также добавил печать в конце main):

Live On Coliru

Class constructor triggered. 
Class moveconstructor triggered. 
Class desctructor triggered. 
Out of main scope. 
Class desctructor triggered. 

Первый вызов деструктора разрушает переехал из- «пустой» экземпляр у наш класс, а второй - при уничтожении самого вектора.

5

Ваш вектор содержит копию объекта, добавляемого к нему через push_back(). Первый вызов деструктора вызван временным созданием, которое вы уничтожаете в конце полного выражения, содержащего вызов push_back(). Второй деструктор вызван копией внутри уничтожаемого вектора, когда сам вектор уничтожается.

Вы можете убедить себя, добавив к диагностической main():

int main() 
{ 
    std::vector<Test> container; 

    container.push_back(Test()); 

    printf("\nThis is before the vector is destroyed..."); 

    return 0; 
} 

Вы можете наблюдать выход в этом live example.

Копия, которую содержит ваш вектор, создается путем вызова автоматически созданного конструктора перемещения для вашего класса (вместо использования конструкции по умолчанию), поэтому вы не видите соответствующую конструктивную диагностику.

Если вы определили свой собственный конструктор перемещения (или конструктор копирования, как показано ниже), чтобы испускать диагностическое, результат будет ближе к тому, что можно было ожидать:

Test(Test const&) 
    { 
     printf("\nCopy construction triggered."); 
    }; 

Опять live example.

2

Для простоты предположим, что вы работаете с C++ 03, а семантика перемещения пока недоступна.

Добавить конструктор копирования, чтобы увидеть, что он также вызвал

Test(const Test&) 
{ 
    printf("\nClass copy constructor triggered."); 
}; 

Выхода

Class constructor triggered. 
Class copy constructor triggered. 
Class destructor triggered. 
Class destructor triggered. 

Итак, есть два объекта, построенные/разрушенный.

Грубо говоря, ваш код равен

int main() 
{ 
    std::vector<Test> container; 

    Test test;     // first object created 
    container.push_back(test); // second object created by copying 
    return 0; 
} 
+1

Это действительно не то же самое, потому что он передает временное прямо в push_back. Поскольку он имеет перегрузку rvalue-ref, может использоваться конструктор перемещения. В вашем случае, поскольку вы определили пользовательский экземпляр-ctor, неявный move-ctor не генерируется. –

+0

@BartekBanachewicz почему вы думаете, что это C++ 11? – Stas

+0

@Stas: Текущий год - 2015 год. Мы принимаем не устаревшую технологию, если не указано иное. –

2

push_back() не вызывает какой-либо деструктор (в данном случае).

два вызова деструктора Test «s являются:

1 - Потому что вы передаете временный к push_back(), так что объект разрушаться, когда push_back() делается

2 - когда в конце программы, поэтому vector уничтожаются и поэтому его содержимое

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