Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cassert>
- #include <vector>
- using namespace std;
- template <typename T>
- class PtrVector {
- public:
- PtrVector() = default;
- // Создаёт вектор указателей на копии объектов из other
- PtrVector(const PtrVector& other) {
- // Резервируем место в vector-е для хранения нужного количества элементов
- // Благодаря этому при push_back не будет выбрасываться исключение
- items_.reserve(other.items_.size());
- try {
- for (auto p : other.items_) {
- // Копируем объект, если указатель на него ненулевой
- auto p_copy = p ? new T(*p) : nullptr; // new может выбросить исключение
- // Не выбросит исключение, т. к. в vector память уже зарезервирована
- items_.push_back(p_copy);
- }
- }
- catch (...) {
- // удаляем элементы в векторе и перевыбрасываем пойманное исключение
- DeleteItems();
- throw;
- }
- }
- // Деструктор удаляет объекты в куче, на которые ссылаются указатели,
- // в векторе items_
- ~PtrVector() {
- DeleteItems();
- }
- // Возвращает ссылку на вектор указателей
- vector<T*>& GetItems() noexcept {
- return items_;
- }
- // Возвращает константную ссылку на вектор указателей
- vector<T*> const& GetItems() const noexcept {
- return items_;
- }
- private:
- void DeleteItems() noexcept {
- for (auto p : items_) {
- delete p;
- }
- }
- vector<T*> items_;
- };
- // Эта функция main тестирует шаблон класса PtrVector
- int main() {
- // Вспомогательный "шпион", позволяющий узнать о своём удалении
- struct DeletionSpy {
- explicit DeletionSpy(bool& is_deleted)
- : is_deleted_(is_deleted) {
- }
- ~DeletionSpy() {
- is_deleted_ = true;
- }
- bool& is_deleted_;
- };
- // Проверяем удаление элементов
- {
- bool spy1_is_deleted = false;
- DeletionSpy* ptr1 = new DeletionSpy(spy1_is_deleted);
- {
- PtrVector<DeletionSpy> ptr_vector;
- ptr_vector.GetItems().push_back(ptr1);
- assert(!spy1_is_deleted);
- // Константная ссылка на ptr_vector
- const auto& const_ptr_vector_ref(ptr_vector);
- // И константная, и неконстантная версия GetItems
- // должны вернуть ссылку на один и тот же вектор
- assert(&const_ptr_vector_ref.GetItems() == &ptr_vector.GetItems());
- }
- // При разрушении ptr_vector должен удалить все объекты, на которые
- // ссылаются находящиеся внутри него указателели
- assert(spy1_is_deleted);
- }
- // Вспомогательный «шпион», позволяющий узнать о своём копировании
- struct CopyingSpy {
- explicit CopyingSpy(int& copy_count)
- : copy_count_(copy_count) {
- }
- CopyingSpy(const CopyingSpy& rhs)
- : copy_count_(rhs.copy_count_) //
- {
- ++copy_count_;
- }
- int& copy_count_;
- };
- // Проверяем копирование элементов при копировании массива указателей
- {
- // 10 элементов
- vector<int> copy_counters(10);
- PtrVector<CopyingSpy> ptr_vector;
- // Подготавливаем оригинальный массив указателей
- for (auto& counter : copy_counters) {
- ptr_vector.GetItems().push_back(new CopyingSpy(counter));
- }
- // Последний элемент содержит нулевой указатель
- ptr_vector.GetItems().push_back(nullptr);
- auto ptr_vector_copy(ptr_vector);
- // Количество элементов в копии равно количеству элементов оригинального вектора
- assert(ptr_vector_copy.GetItems().size() == ptr_vector.GetItems().size());
- // копия должна хранить указатели на новые объекты
- assert(ptr_vector_copy.GetItems() != ptr_vector.GetItems());
- // Последний элемент исходного массива и его копии - нулевой указатель
- assert(ptr_vector_copy.GetItems().back() == nullptr);
- // Проверяем, что элементы были скопированы (копирующие шпионы увеличивают счётчики копий).
- assert(all_of(copy_counters.begin(), copy_counters.end(), [](int counter) {
- return counter == 1;
- }));
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement