Advertisement
kutuzzzov

Урок 8-2 Копирование объектов ч 2

Dec 8th, 2022
1,302
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.69 KB | None | 0 0
  1. #include <cassert>
  2. #include <iostream>
  3. #include <stdexcept>
  4. #include <exception>
  5.  
  6. using namespace std;
  7.  
  8. // Умный указатель, удаляющий связанный объект при своём разрушении.
  9. // Параметр шаблона T задаёт тип объекта, на который ссылается указатель
  10. template <typename T>
  11. class ScopedPtr {
  12. public:
  13.     // Конструктор по умолчанию создаёт нулевой указатель,
  14.     // так как поле ptr_ имеет значение по умолчанию nullptr
  15.     ScopedPtr() = default;
  16.  
  17.     // Создаёт указатель, ссылающийся на переданный raw_ptr.
  18.     // raw_ptr ссылается либо на объект, созданный в куче при помощи new,
  19.     // либо является нулевым указателем
  20.     // Спецификатор noexcept обозначает, что метод не бросает исключений
  21.     explicit ScopedPtr(T* raw_ptr) noexcept {
  22.         // Реализуйте самостоятельно
  23.         ptr_ = raw_ptr;
  24.     }
  25.  
  26.     // Удаляем у класса конструктор копирования
  27.     ScopedPtr(const ScopedPtr&) = delete;
  28.  
  29.     // Деструктор. Удаляет объект, на который ссылается умный указатель.
  30.     ~ScopedPtr() {
  31.         // Реализуйте тело деструктора самостоятельно
  32.         delete ptr_;
  33.     }
  34.  
  35.     // Возвращает указатель, хранящийся внутри ScopedPtr
  36.     T* GetRawPtr() const noexcept {
  37.         // Напишите код метода самостоятельно
  38.         return ptr_;
  39.     }
  40.  
  41.     // Прекращает владение объектом, на который ссылается умный указатель
  42.     // Возвращает прежнее значение "сырого" указателя и устанавливает поле ptr_ в null
  43.     T* Release() noexcept {
  44.         // Реализуйте самостоятельно
  45.         ptr2_ = ptr_;
  46.         ptr_ = nullptr;
  47.         return ptr2_;
  48.     }
  49.  
  50.     // Оператор приведения к типу bool позволяет узнать, ссылается ли умный указатель
  51.     // на какой-либо объект
  52.     explicit operator bool() const noexcept {
  53.         // Реализуйте самостоятельно
  54.         if (ptr_ != nullptr) {
  55.             return true;
  56.         } else {
  57.             return false;
  58.         }
  59.     }
  60.  
  61.     // Оператор разыменования возвращает ссылку на объект
  62.     // Выбрасывает исключение std::logic_error, если указатель нулевой
  63.     T& operator*() const {
  64.         // Реализуйте самостоятельно
  65.         if (ptr_ != nullptr) {
  66.                 return *ptr_;
  67.         } else {
  68.             throw logic_error("empty ScopedPtr"s);
  69.         }
  70.     }
  71.  
  72.     // Оператор -> должен возвращать указатель на объект
  73.     // Выбрасывает исключение std::logic_error, если указатель нулевой
  74.     T* operator->() const {
  75.         // Реализуйте самостоятельно
  76.         if (ptr_ != nullptr) {
  77.                 return ptr_;
  78.         } else {
  79.             throw logic_error("empty ScopedPtr"s);
  80.         }
  81.     }
  82.    
  83. private:
  84.     T* ptr_ = nullptr;
  85.     T* ptr2_ = nullptr;
  86. };
  87.  
  88. // Этот main тестирует класс ScopedPtr
  89. int main() {
  90.     // Проверка работы оператора приведения к типу bool
  91.     {
  92.         // Для нулевого указателя приведение к типу bool возвращает false
  93.         const ScopedPtr<int> empty_ptr;
  94.         assert(!empty_ptr);
  95.  
  96.         // Для ненулевого указателя приведение к типу bool возвращает true
  97.         const ScopedPtr<int> ptr_to_existing_object(new int(0));
  98.         assert(ptr_to_existing_object);
  99.  
  100.         static_assert(noexcept(static_cast<bool>(ptr_to_existing_object)));
  101.     }
  102.  
  103.     // Проверка работы оператора разыменования *
  104.     {
  105.         string* raw_ptr = new string("hello");
  106.         ScopedPtr<string> smart_ptr(raw_ptr);
  107.         // Ссылка, возвращаемая оператором разыменования должна ссылаться на объект,
  108.         // на который указывает умный указатель
  109.         assert(&*smart_ptr == raw_ptr);
  110.  
  111.         try {
  112.             ScopedPtr<int> empty_ptr;
  113.             // При попытке разыменовать пустой указатель должно быть выброшено
  114.             // исключение logic_error
  115.             *empty_ptr;
  116.             // Сюда попасть мы не должны
  117.             assert(false);
  118.         } catch (const logic_error&) {
  119.             // мы там, где нужно
  120.         } catch (...) {
  121.             // Других исключений выбрасываться не должно
  122.             assert(false);
  123.         }
  124.     }
  125.  
  126.     // Проверка работы оператора ->
  127.     {
  128.         string* raw_ptr = new string("hello");
  129.         ScopedPtr<string> smart_ptr(raw_ptr);
  130.         // Доступ к членам класса через умный указатель должен быть аналогичен
  131.         // доступу через "сырой" указатель
  132.         assert(smart_ptr->data() == raw_ptr->data());
  133.  
  134.         try {
  135.             ScopedPtr<string> empty_ptr;
  136.             // При попытке разыменовать пустой указатель должно быть выброшено
  137.             // исключение logic_error
  138.             empty_ptr->clear();
  139.             // Сюда попасть мы не должны
  140.             assert(false);
  141.         } catch (const logic_error&) {
  142.             // мы там, где нужно
  143.         } catch (...) {
  144.             // Других исключений выбрасываться не должно
  145.             assert(false);
  146.         }
  147.     }
  148.  
  149.     // Пример использования
  150.     {
  151.         // На этой структуре будет проверяться работа умного указателя
  152.         struct Object {
  153.             Object() {
  154.                 cout << "Object is default constructed"s << endl;
  155.             }
  156.             void DoSomething() {
  157.                 cout << "Doing something"s << endl;
  158.             }
  159.             ~Object() {
  160.                 cout << "Object is destroyed"s << endl;
  161.             }
  162.         };
  163.  
  164.         // Сконструированный по умолчанию указатель ссылается на nullptr
  165.         ScopedPtr<Object> empty_smart_ptr;
  166.         // Перегруженный оператор приведения к типу bool вернёт false для пустого указателя
  167.         assert(!empty_smart_ptr);
  168.  
  169.         ScopedPtr<Object> smart_ptr(new Object());
  170.         // Перегруженный оператор bool вернёт true для указателя, ссылающегося на объект
  171.         assert(smart_ptr);
  172.  
  173.         // Проверка оператора разыменования
  174.         (*smart_ptr).DoSomething();
  175.         // Проверка оператора доступа к членам класса
  176.         smart_ptr->DoSomething();
  177.     }
  178. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement