data()
не требуется, поскольку это будет сделано автоматически для вектора перед вводом конструктора. Вам нужно только инициализировать элементы, являющиеся типами POD или типами, которые не имеют конструктора по умолчанию (или ссылок, констант и т. Д.).
Вы можете инициализировать вектор количеством элементов, которые есть у другого, чтобы вектор не изменял свой размер по мере роста. Если вы этого не сделаете, вы начинаете с небольшого вектора и постепенно увеличиваете его размер до целевого значения путем перераспределения и перераспределения. Это сделает вектор с самого начала правильным размером:
B::B(const B& orig) : data(orig.data.size()) {
for (std::size_t i = 0; i < orig.data.size(); ++i)
data[i] = new A(*orig.data[i]);
}
Обратите внимание, что вы больше не используете push_back
, потому что вектор уже заполнен orig.data.size()
количеством элементов, которые созданы по умолчанию (в случае указателей это NULL
).
Это также обрезает код, потому что вы можете использовать целое число для его итерации вместо итератора.
Если вы действительно хотите использовать итераторы, вы можете сделать
B::B(const B& orig) : data(orig.data.size()) {
// auto is preferable here but I don't know if your compiler supports it
vector<A*>::iterator thisit = data.begin();
vector<A*>::const_iterator thatit = orig.data.cbegin();
for (; thatit != orig.data.cend(); ++thisit, ++thatit)
*thisit = new A(**thatit);
}
Преимущество этого в том, что он будет работать с другими типами контейнеров (например, list
), просто изменяя типы итераторов (но, конечно, это исчезнет, если у вас будет auto
).
Если вы хотите добавить исключительную безопасность, вам нужен блок try/catch
:
B::B(const B& orig) : data(orig.data.size()) {
try {
// auto is preferable here but I don't know if your compiler supports it
vector<A*>::iterator thisit = data.begin();
vector<A*>::const_iterator thatit = orig.data.cbegin();
for (; thatit != orig.data.cend(); ++thisit, ++thatit)
*thisit = new A(**thatit);
} catch (...) {
for (vector<A*>::iterator i = data.begin(); i != data.end(); ++i)
if (!*i)
break;
else
delete *i;
throw;
}
}
Таким образом, у вас не будет утечки памяти, если один из вызовов new
вызовет исключение. Конечно, вы можете использовать try/catch
вместе с способом без итераторов, если вы предпочитаете делать это таким образом.