Files
SH-Quizzes/ACMOJ-2090.hpp
2023-12-23 22:23:48 +08:00

162 lines
3.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#ifndef SRC_HPP
#define SRC_HPP
#include <initializer_list>
#include <stdexcept>
// 以上是你所需要的头文件,如果你想使用其它头文件,请询问助教
// 禁止使用 std::shared_ptr 与 std::any
namespace sjtu {
class any_ptr {
class Info_Base {
public:
int counter;
virtual ~Info_Base() {}
};
template <class T>
class Info : public Info_Base {
public:
T *ptr;
Info(T *ptr) : ptr(ptr) {}
~Info() override { delete ptr; }
};
Info_Base *info = nullptr;
public:
/**
* @brief 默认构造函数,行为应与创建空指针类似
*
*/
any_ptr() {}
/**
* @brief
* 拷贝构造函数,要求拷贝的层次为浅拷贝,即该对象与被拷贝对象的内容指向同一块内存
* @note 若将指针作为参数传入,则指针的生命周期由该对象管理
* @example
* any_ptr a = make_any_ptr(1);
* any_ptr b = a;
* a.unwrap<int> = 2;
* std::cout << b << std::endl; // 2
* @param other
*/
any_ptr(const any_ptr &other) {
info = other.info;
if (info) info->counter++;
}
template <class T>
any_ptr(T *ptr) {
info = new Info<T>(ptr);
info->counter = 1;
}
/**
* @brief
* 析构函数,注意若一块内存被多个对象共享,那么只有最后一个析构的对象需要释放内存
* @example
* any_ptr a = make_any_ptr(1);
* {
* any_ptr b = a;
* }
* std::cout << a << std::endl; // valid
* @example
* int *p = new int(1);
* {
* any_ptr a = p;
* }
* std::cout << *p << std::endl; // invalid
*
*/
~any_ptr() {
if (info) {
info->counter--;
if (info->counter == 0) {
delete info;
}
}
}
/**
* @brief
* 拷贝赋值运算符,要求拷贝的层次为浅拷贝,即该对象与被拷贝对象的内容指向同一块内存
* @note 应与指针拷贝赋值运算符的语义相近
* @param other
* @return any_ptr&
*/
any_ptr &operator=(const any_ptr &other) {
if (info) {
info->counter--;
if (info->counter == 0) {
delete info;
}
}
info = other.info;
if (info) info->counter++;
return *this;
}
template <class T>
any_ptr &operator=(T *ptr) {
if (info) {
info->counter--;
if (info->counter == 0) {
delete info;
}
}
info = new Info<T>(ptr);
info->counter = 1;
return *this;
}
/**
* @brief 获取该对象指向的值的引用
* @note 若该对象指向的值不是 T 类型,则抛出异常 std::bad_cast
* @example
* any_ptr a = make_any_ptr(1);
* std::cout << a.unwrap<int>() << std::endl; // 1
* @tparam T
* @return T&
*/
template <class T>
T &unwrap() {
Info<T> *info_t = dynamic_cast<Info<T> *>(info);
if (info_t)
return *(info_t->ptr);
else
throw std::bad_cast();
}
// 某一个 any_ptr 类对象可能为 const请你补充 unwrap 函数
template <class T>
const T &unwrap() const {
Info<T> *info_t = dynamic_cast<Info<T> *>(info);
if (info_t)
return *(info_t->ptr);
else
throw std::bad_cast();
}
};
/**
* @brief 由指定类型的值构造一个 any_ptr 对象
* @example
* any_ptr a = make_any_ptr(1);
* any_ptr v = make_any_ptr<std::vector<int>>(1, 2, 3);
* any_ptr m = make_any_ptr<std::map<int, int>>({{1, 2}, {3, 4}});
* @tparam T
* @param t
* @return any_ptr
*/
template <class T>
any_ptr make_any_ptr(const T &t) {
return any_ptr(new T(t));
}
// 某些 any_ptr 类对象可能由不定长参数或初始化列表构造,请你参照上方的 example
// 补充 make_any_ptr 函数,我们会有一个特殊的测试点测试你的程序是否完成要求
template <class T, class... Args>
any_ptr make_any_ptr(Args... args) {
return any_ptr(new T(std::forward<Args>(args)...));
}
} // namespace sjtu
#endif