Advertisement
AlexDanilin

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

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