Конструктор копирования, вызываемый много раз при вставке данных в вектор

#c

#c

Вопрос:

 #include <iostream>
#include <vector>
using namespace std;
class base
{
    int x;
public:
    base(int k){x =k; }
    void display()
    {
        cout<<x<<endl;
    }

    base(const baseamp;)
    {
        cout<<"base copy constructor:"<<endl;
    }
};
int main()
{
    vector<base> v;
    base obase[5]={4,14,19,24,29};
    for(int i=0; i<5; i  )
    {
        v.push_back(obase[i]);
    }

}
  

Когда данные вставляются в вектор, копирование этих данных отправляется в вектор с помощью конструктора копирования.

Когда я запускаю эту программу,

  1. для первой вставки (i=0) вызывается конструктор копирования один раз.
  2. для второй вставки (i = 1) вызывается конструктор копирования два раза
  3. для третьей вставки (i = 3) вызывается конструктор копирования три раза
  4. для четвертой вставки (i = 3) вызывается конструктор копирования четыре раза
  5. для пятой вставки (i = 4) вызывается конструктор копирования пять раз

Пожалуйста, кто-нибудь может сказать мне, почему это происходит? Для каждой вставки не следует вызывать конструктор копирования только один раз?

Ответ №1:

вызывает push_back() увеличение размера вектора по мере необходимости, что включает копирование содержимого вектора. Поскольку вы уже знаете, что он будет содержать пять элементов, либо v.reserve(5); непосредственно перед циклом, либо используйте конструктор range:

 base obase[5]={4,14,19,24,29};
vector<base> v(obase, obase 5);
  

Комментарии:

1. Другим обходным путем является использование std::deque<> вместо std::vector<> , если не требуется компоновка непрерывной памяти.

Ответ №2:

Ваш конструктор копирования неисправен, вы забыли фактически скопировать данные 🙂

 base(const baseamp; that) : x(that.x)
{
    cout << "base copy constructorn";
}
  

Кроме того, если у вас современный компилятор, вы можете написать конструктор перемещения и узнать что-то новое:

 base(baseamp;amp; that) : x(that.x)
{
    cout << "base move constructorn";
}
  

Комментарии:

1. Вы абсолютно правы. Пожалуйста, не могли бы вы также объяснить, зачем «const» нужен в конструкторе копирования. если я не использую его, это выдает ошибку компиляции.

2. @Alok: Потому что ссылки на неконстантные значения не привязываются к rvalues. Если это звучит слишком технически для вас, не волнуйтесь. На практике все конструкторы копирования имеют const, потому что они только считывают из источника и не изменяют его. Не было бы смысла удалять const .

3. Большое спасибо, очень приятное описание

Ответ №3:

Если v необходимо изменить размер его внутреннего буфера, он обычно выделяет совершенно новую область памяти, поэтому ему необходимо скопировать все объекты, которые ранее были в векторе, в новое местоположение. Это делается с помощью обычного копирования, поэтому вызывается конструктор копирования.

Вам следует вызвать reserve() вектор, чтобы заранее зарезервировать хранилище, если вы можете оценить, сколько элементов вам понадобится.

Обратите внимание, что поведение изменения размера / увеличения std::vector зависит от реализации, поэтому ваш пример кода будет выдавать разные результаты с разными реализациями стандартной библиотеки.

Комментарии:

1. Пожалуйста, не могли бы вы также объяснить, почему в конструкторе копирования мне нужен const ketyword? если я его не использую, это выдает ошибку компиляции?