В
v1=x;
Происходят две вещи:
- Совершенно новый временный
vector
построен с использованием vector(T *a)
. Этот временный vector
никак не связан с v1
- Временный
vector
присваивается v1
с использованием сгенерированного компилятором оператора присваивания по умолчанию.
К сожалению, vector(T *a)
не выделяет v
и не назначает существующее хранилище для v
. Так как v
не указывает на действительный объект, разыменование приводит к неопределенному поведению и может сделать что угодно. На компьютере спрашивающего выглядит, как будто v[i]=a[i];
записывает в недействительную память и вызывает сбой Если бы нам всем так повезло.
Решение
Выделите немного памяти для v
vector(T *a): v(new T[size])
{
for(int i=0; i<size; i++){
cout << "B" << endl;
v[i]=a[i];
}
cout << "vector 1-arg ctor" << endl;
}
В качестве примера я использовал List Initializer List . Это трагически недоучено и удивительно полезно.
Не пытайтесь
vector(T *a): v(a)
{
}
хотя это выглядит очень заманчиво. Деструктор vector
не может быть записан в ближайшем будущем, чтобы утечки памяти не могли сообщать статически размещенный массив x
, который нельзя delete
редактировать без вызова Undefined Behavior из динамического размещения, предоставляемого конструктором по умолчанию, который должен быть delete
ed.
И так как тема деструкторов возникла, важно знать о Правиле Трех .
Шаг 2 из v1=x;
выполняет назначение. Сгенерированный компилятором оператор присваивания по умолчанию очень прост и очень глуп. Он точно копирует то, что находится в одном vector
, в другое. Если он видит указатель, он копирует адрес, а не то, на что он указывает. Что бы ни указывало на объект назначения, оно не delete
ed и, вероятно, потеряно. Это оставляет вас с двумя объектами, указывающими на одну и ту же память. Изменение одного объекта теперь может изменить другой, и наступает хаос.
После этого назначения v1
v
будет заменено временным vector
, утечка первоначального выделения памяти v1
. Хуже того, временный vector
соответствует названию и быстро выходит из области видимости. Как только у vector
будет функционирующий деструктор, временное устройство возьмет его с собой v
, и, поскольку v1
и временное теперь указываются в том же распределении памяти, v1
'v
остается указанным в неверной памяти.
Требуется оператор присваивания для устранения этой путаницы. См. Copy и Swap Idiom для очень простого, очень безопасного способа написать оператор присваивания.