Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <algorithm>
- #include <cassert>
- #include <stdexcept>
- #include <vector>
- #include <iostream>
- using namespace std;
- // Используйте эту заготовку PtrVector или замените её на свою реализацию
- 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();
- }
- PtrVector& operator=(const PtrVector& rhs)
- {
- if (this != &rhs)
- {
- auto rhs_copy(rhs);
- swap_(rhs_copy);
- }
- return *this;
- }
- void swap_(PtrVector& other) noexcept
- {
- swap(other.items_, this->items_);
- }
- // Возвращает ссылку на вектор указателей
- 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_;
- };
- //#include "octopus.h"
- using namespace std;
- // Эта функция main тестирует шаблон класса PtrVector
- int main() {
- struct CopyingSpy {
- CopyingSpy(int& copy_count, int& deletion_count)
- : copy_count_(copy_count)
- , deletion_count_(deletion_count) {
- }
- CopyingSpy(const CopyingSpy& rhs)
- : copy_count_(rhs.copy_count_) // счётчик копирований
- , deletion_count_(rhs.deletion_count_) // счётчик удалений
- {
- if (rhs.throw_on_copy_) {
- throw runtime_error("copy construction failed"s);
- }
- ++copy_count_;
- }
- ~CopyingSpy() {
- ++deletion_count_;
- }
- void ThrowOnCopy() {
- throw_on_copy_ = true;
- }
- private:
- int& copy_count_;
- int& deletion_count_;
- bool throw_on_copy_ = false;
- };
- // Проверка присваивания
- {
- int item0_copy_count = 0;
- int item0_deletion_count = 0;
- {
- PtrVector<CopyingSpy> v;
- v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
- v.GetItems().push_back(nullptr);
- {
- PtrVector<CopyingSpy> v_copy;
- v_copy = v;
- assert(v_copy.GetItems().size() == v.GetItems().size());
- assert(v_copy.GetItems().at(0) != v.GetItems().at(0));
- assert(v_copy.GetItems().at(1) == nullptr);
- assert(item0_copy_count == 1);
- assert(item0_deletion_count == 0);
- }
- assert(item0_deletion_count == 1);
- }
- assert(item0_deletion_count == 2);
- }
- // Проверка корректности самоприсваивания
- {
- int item0_copy_count = 0;
- int item0_deletion_count = 0;
- PtrVector<CopyingSpy> v;
- v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
- CopyingSpy* first_item = v.GetItems().front();
- v = v;
- assert(v.GetItems().size() == 1);
- // При самоприсваивании объекты должны быть расположены по тем же адресам
- assert(v.GetItems().front() == first_item);
- assert(item0_copy_count == 0);
- assert(item0_deletion_count == 0);
- }
- // Проверка обеспечения строгой гарантии безопасности исключений при присваивании
- {
- int item0_copy_count = 0;
- int item0_deletion_count = 0;
- int item1_copy_count = 0;
- int item1_deletion_count = 0;
- // v хранит 2 элемента
- PtrVector<CopyingSpy> v;
- v.GetItems().push_back(new CopyingSpy(item0_copy_count, item0_deletion_count));
- v.GetItems().push_back(new CopyingSpy(item1_copy_count, item1_deletion_count));
- int other_item0_copy_count = 0;
- int other_item0_deletion_count = 0;
- // other_vector хранит 1 элемент, при копировании которого будет выброшено исключение
- PtrVector<CopyingSpy> other_vector;
- other_vector.GetItems().push_back(new CopyingSpy(other_item0_copy_count, other_item0_deletion_count));
- other_vector.GetItems().front()->ThrowOnCopy();
- // Сохраняем массив указателей
- auto v_items(v.GetItems());
- try {
- v = other_vector;
- // Операция должна выбросить исключение
- assert(false);
- }
- catch (const runtime_error&) {
- }
- // Элементы массива должны остаться прежними
- assert(v.GetItems() == v_items);
- assert(item0_copy_count == 0);
- assert(item1_copy_count == 0);
- assert(other_item0_copy_count == 0);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement