101 lines
3.0 KiB
C++
101 lines
3.0 KiB
C++
#pragma once
|
||
#include <new>
|
||
#include <utility>
|
||
// 你不可以使用其他任何头文件
|
||
|
||
namespace sjtu {
|
||
|
||
/**
|
||
* @brief 一个可以在离开作用域之后自动归还内存的指针。
|
||
* unique_ptr <_Tp> 行为应该和普通指针 _Tp * 几乎一致。
|
||
* @tparam _Tp 模板参数,指针指向的类型。
|
||
*/
|
||
template <typename _Tp>
|
||
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<int>) <= sizeof(void *));
|
||
|
||
// // 创建一个 unique_ptr,指向一个用 new 分配的 _Tp 对象
|
||
// template <typename _Tp>
|
||
// 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 <typename _Tp, typename... Args>
|
||
unique_ptr<_Tp> make_unique(Args &&...args) {
|
||
return std::move(unique_ptr<_Tp>(new _Tp(std::forward<Args>(args)...)));
|
||
}
|
||
} // namespace sjtu
|