#pragma once #include #include // 你不可以使用其他任何头文件 namespace sjtu { /** * @brief 一个可以在离开作用域之后自动归还内存的指针。 * unique_ptr <_Tp> 行为应该和普通指针 _Tp * 几乎一致。 * @tparam _Tp 模板参数,指针指向的类型。 */ template class unique_ptr { private: // 你可以自由地增加成员变量和成员函数 _Tp *ptr=nullptr; public: // 构造一个空的指针 (nullptr) unique_ptr() : ptr(nullptr){} // 同一个指针不能被多个 unique_ptr 指向 unique_ptr(const unique_ptr &) = delete; // 移动构造函数。移交所有权。 // 注意移交后要把 other 置空。 unique_ptr(unique_ptr &&other) { ptr = other.ptr; other.ptr = nullptr; } // 析构函数。释放指针指向的内存。 // 需要注意,delete nullptr 是安全的。 ~unique_ptr() { delete ptr; } // 同一个指针不能被多个 unique_ptr 指向 unique_ptr &operator=(const unique_ptr &) = delete; // 移动赋值运算符。移交所有权。 // 注意移交后要把 other 置空。 unique_ptr &operator=(unique_ptr &&other) { if (this == &other) return *this; delete ptr; ptr = other.ptr; other.ptr = nullptr; return *this; } // 接管一个普通 _Tp 类型的指针的所有权 explicit unique_ptr(_Tp *address) : ptr(address) {} // 重置为空指针。同时释放指针指向的内存。 void reset() { delete ptr; ptr = nullptr; } // 转移所有权,返回指针指向的对象的地址 // 同时,自己要置空。 _Tp *release() { _Tp *ptr_tmp = ptr; ptr = nullptr; return ptr_tmp; } // 返回指针指向的对象的地址 // 所有权不转移。 _Tp *get() const noexcept { return ptr; } // 重载 * 运算符(解引用),返回指针指向的对象的引用 _Tp &operator*() noexcept { return *ptr; } // 重载 -> 运算符(成员访问),返回指针指向的对象的地址 _Tp *operator->() noexcept { return ptr; } }; // 对于一个 unique_ptr,你最多只能存一个指针 static_assert(sizeof(unique_ptr) <= sizeof(void *)); // // 创建一个 unique_ptr,指向一个用 new 分配的 _Tp 对象 // template // unique_ptr <_Tp> make_unique(const _Tp &val) // { // return std::move(unique_ptr<_Tp>(new _Tp(val))); // } // Bonus: (不作为考察内容) // (如果写了,请删除上面的这个 make_unique) // (否则,请删除下面的这个 make_unique) // 可变长参数列表 + 万能引用 // 创建一个 unique_ptr,指向一个用 new 分配的 _Tp 对象 // 参数列表长度可变,且有左值引用和右值引用两种版本 // 当传入左值 T &, Args 类型被推导为 T & // 当传入右值 T &&,Args 类型被推导为 T // 你需要了解如何用 std::forward 实现完美转发 template unique_ptr<_Tp> make_unique(Args &&...args) { return std::move(unique_ptr<_Tp>(new _Tp(std::forward(args)...))); } } // namespace sjtu