Opened 4 years ago
Closed 4 years ago
#827 closed ожидаются исправления (задача сдана)
WW #12
Reported by: | Brilliantov Kirill | Owned by: | Sokolov Viacheslav |
---|---|---|---|
Component: | WW_vector | Version: | 2.0 |
Keywords: | Cc: |
Description
Change History (4)
comment:1 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
comment:2 Changed 4 years ago by
Type: | ожидаются исправления → ожидается проверка |
---|---|
Version: | 1.0 → 2.0 |
comment:3 Changed 4 years ago by
Type: | ожидается проверка → ожидаются исправления |
---|
153 if (vholder_.size_ >= vholder_.capacity_) {
154 reserve(vholder_.capacity_ == 0 ? 1 : 2 * vholder_.capacity_);
155 }
проще безусловно reserve(size() + 1)
130 if (n < vholder_.capacity_)
131 return;
<=
129 void my_vector<T>::reserve(std::size_t n) {
текущая реализация нарушает требование
Методы и конструкторы, которые увеличивают capacity, делают его равным минимальной достаточной степени двойки.
т.е. reserve могут позвать на произвольное значение, а внутри метода должно получиться так, что новое capacity - минимальная необходимая степень двойки
114 vholder_.ctor_elems(n - vholder_.size_);
здесь может произойти исключение, нарушится строгая гарантия
127 for (size_t i = 0; i < n - vholder_.size_; i++, v.size_++) {
128 new (v.array_ + vholder_.size_ + i) T{};
129 }
если здесь произойдет исключение, то будет нарушено соглашение "первые size полей инициализированы", что используется в деструкторе. Стоит обработать через try.. catch.. throw;
118 vector_holder v{2 * vholder_.capacity_};
не факт, что этого достаточно, чтобы вместить n элементов
34 new (array_ + size_++) T(data[i]);
здесь и в аналогичных местах size_ нужно увеличивать строго после выполнения конструктора, потому что если из него вылетит исключение, то size_ будет больше, чем реально сконструировано объектов, что важно в деструкторе
comment:4 Changed 4 years ago by
Resolution: | → задача сдана |
---|---|
Status: | assigned → closed |
Для include/my_vector_impl.hpp не хватает include guard-а
10 std::ostream &operator<<(std::ostream &, const product::Product &);
зачем помещать в глобальное пространство имен?
noexcept
30 assert(vec1.capacity() == ceil_power_of_two(vec1.size()));
можно и size заодно проверить
не все методы покрыты тестами, например, rvalue и [] не тестируется
noexcept
const& noexcept - непонятно, зачем копировать
30 void clear();
noexcept
непонятно, зачем это в my_vector.h
зачем выносить в глобальное пространство имен?
лучше (с точки зрения организации кода, но не с точки зрения производительности) не inline, а в .cpp
какое здесь ожидается исключение?
не очень хорошо с точки зрения потребления памяти, лучше было бы создавать по одному
162 vector_holder v{0};
163 vholder_.swap(v);
при этом capacity станет 0. У std::vector же capacity не меняется; не очень понятно, в какой ситуации capacity=0 - желаемое поведение.
156 template <typename T> void my_vector<T>::pop_back() {
с такой реализацией - noexcept
120 if (n < vholder_.capacity_)
121 return;
<=
18 template <typename T> void my_vector<T>::reserve(std::size_t n) {
119 assert(n == ceil_power_of_two(n));
зачем это ограничение?
resize реализован неоптимально.
1) если n <= size_, то нужно просто освободить память.
2) если size_ < n < capacity_, то аллокация памяти не нужна
3) даже если аллокация нужна, стоит использовать std::move, а не копирование. Для этого нужно сначала заполнить конец массива, заполнив значениями по умолчанию, а потом сделать move уже имеющихся элементов.
В push_back не нужно ничего копировать. reserve + move дают нужный эффект, единственное возможное исключение - это bad_alloc.
для примитивных типов память останется неинициализированной. Нужно использовать
https://stackoverflow.com/a/7546745