SJTU CS1958-01 2026Fall 第二次大作业
开始项目前,建议先阅读智能指针:从入门到入土
本项目要实现的内容是一个类模板,可能有类似于template <typename T>的语句,你可以在理解的时候将T视作某一种特殊的类型名称(或者视为int)。根据这一规则,被包装的原始指针的类型就是T*。
你需要构造的unique_ptr类模板的要求包括:
-
默认构造函数,内部指针默认应当为
nullptr:UniquePtr<int> ptr; -
能够支持将普通指针转换成
unique_ptr的构造函数:UniquePtr<int> ptr{new int{10}};
-
unique_ptr间的移动构造函数,并禁止拷贝构造函数的存在:UniquePtr<int> ptr2{ptr1}; // compile error!
-
在类外编写类似于
std::make_unique的函数模版,要求能够支持对任意类型、任意数量的参数的unique_ptr构造,且能触发UniquePtr类的移动构造函数:UniquePtr<int> ptr{make_unique<int>(10)}; UniquePtr<std::vector<int>> ptr2{make_unique<std::vector<int>>(2,3)};
-
重载运算符
operator=,实现unique_ptr间的移动赋值并禁止拷贝赋值:UniquePtr<int> ptr1{new int{10}}; UniquePtr<int> ptr2{new int{11}}; ptr2 = ptr1; // compile error!
-
析构函数
~UniquePtr()删除动态指针并将其置为nullptr(思考:为什么要置空) -
实现
get()函数用以返回存储在类中的原始指针:UniquePtr<int> ptr{new int{10}}; std::cout << ptr.get() << std::endl; // output: raw pointer stored in the class
-
重载类型转换符
bool()来判断指针是否为空,非空返回 true,空返回 false:UniquePtr<std::string> ptr{new std::string{"hello"}}; std::cout << bool(ptr) << std::endl; // output: true -
重载解引用运算符
operator*,实现与普通指针相同的解引用功能:UniquePtr<int> ptr{new int{10}}; std::cout << *ptr << std::endl; // output: 10
-
重载间接引用运算符
operator->,实现与普通指针相同的间接引用功能:UniquePtr<std::string> ptr{new std::string{"hello"}}; std::cout << ptr->length() << std::endl; // output: 5 -
实现
reset()函数,包括以下两种参数形式:void reset()删除原有指针并分配nullptr给它void reset(T* p)删除原有指针并分配p给它
UniquePtr<std::string> ptr{new std::string{"hello"}}; ptr.reset(new std::string{"nice"}); std::cout << *ptr << std::endl; // output: nice -
实现
release函数,让对象脱离unique_ptr的管理,并返回一个指向原对象的普通指针(交给使用者进行内存管理)。在此期间,unique_ptr类不删除原有指针。UniquePtr<double> ptr{new double{1.567}}; double *tmp{ptr.release()}; std::cout << *tmp << std::endl; // output: 1.567 delete tmp; // manual deletion
shared_ptr 中的要求包括:
-
默认构造函数,内部指针默认应当为
nullptr:SharedPtr<int> ptr; -
实现能够支持将普通指针和
unique_ptr转换成shared_ptr的构造函数:UniquePtr<int> ptr{new int{1}}; SharedPtr<int> sp1{new int{10}}; SharedPtr<int> sp2{ptr};
-
实现
shared_ptr间的移动构造函数与拷贝构造函数SharedPtr<int> ptr2{ptr1}; // compile success
-
在类外编写类似于
std::make_shared的函数模版,要求能够支持对任意类型、任意数量的参数的shared_ptr构造,且能触发SharedPtr类的移动构造函数:SharedPtr<int> ptr{make_shared<int>(10)};
-
析构函数
~SharedPtr()删除动态指针并将其置为nullptr -
实现
use_count()函数用以返回指向当前的对象的所有shared_ptr实例数:SharedPtr<int> ptr1{make_shared<int>(10)}; std::cout << ptr1.use_count() << std::endl; // output: 1 SharedPtr<int> ptr2{ptr1}; std::cout << ptr1.use_count() << std::endl; // output: 2 std::cout << ptr2.use_count() << std::endl; // output: 2
-
实现
get()函数用以返回存储在类中的原始指针:SharedPtr<int> ptr{new int{10}}; std::cout << ptr.get() << std::endl; // output: raw pointer of the class
-
重载类型转换符
bool()来判断指针是否为空,非空返回 true,空返回 false:SharedPtr<std::string> ptr{new std::string{"hello"}}; std::cout << bool(ptr) << std::endl; // output: 1 -
重载解引用运算符
operator*,实现与普通指针相同的解引用功能:SharedPtr<int> ptr{new int{10}}; std::cout << *ptr << std::endl; // output: 10
-
重载间接引用运算符
operator->,实现与普通指针相同的间接引用功能:SharedPtr<std::string> ptr{new std::string{"hello"}}; std::cout << ptr->length() << std::endl; // output: 5 -
重载运算符
operator=,实现shared_ptr间的移动赋值与拷贝赋值:SharedPtr<int> ptr1{new int{10}}; SharedPtr<int> ptr2{new int{11}}; ptr2 = ptr1;
-
实现
reset()函数,包括实现以下两种参数形式:void reset()删除原有指针并分配nullptr给它void reset(T* p)删除原有指针并分配p给它
SharedPtr<std::string> ptr{new std::string{"hello"}}; ptr.reset(new std::string{"nice"}); std::cout << *ptr << std::endl; // output: nice
为此,你需要构造的 weak_ptr 模版类的要求包括:
-
默认构造函数,内部指针默认应当为
nullptr:WeakPtr<int> wp; -
能够支持将
shared_ptr转换成weak_ptr的构造函数:SharedPtr<int> sp{new int{10}}; WeakPtr<int> wp{sp};
-
移动构造函数与拷贝构造函数,注意在拷贝构造中可以通过
shared_ptr构造weak_ptrWeakPtr<int> wp1{sp}; WeakPtr<int> wp2{wp1}; // compile success WeakPtr<int> wp2{std::move(wp1)}; // compile success
-
拥有析构函数
~WeakPtr()删除动态指针并将其置为nullptr -
重载运算符
operator=,实现移动赋值与拷贝赋值,注意在拷贝赋值中可以将shared_ptr赋给weak_ptrWeakPtr<int> wp1, wp2; SharedPtr<int> sp{new int{10}}; wp1 = sp; // compile success wp2 = wp1; // compile success WeakPtr<int> wp1{sp}, wp2; wp2 = std::move(wp1); // compile success
-
重载类型转换符
bool()来判断指针是否为空,非空返回 true,空返回 false:WeakPtr<int> wp; SharedPtr<int> sp{new int{10}}; wp = sp; std::cout << bool(wp) << std::endl; // output: 1
-
实现
use_count()函数,用以返回指向当前的对象的所有shared_ptr实例数 -
实现
lock()函数用以转换weak_ptr为shared_ptr,注意这会产生一个新的shared_ptr,引发计数器变化。如果对象已被删除,则返回一个空的shared_ptr:WeakPtr<int> wp{sp}; SharedPtr<int> sp2 = wp.lock(); if(sp2) { std::cout << *sp2 << std::endl; // Use the object safely }
-
实现
expired()函数用以检查weak_ptr所指向的对象是否已被删除,返回true表示被删除,返回false表示没有被删除:WeakPtr<int> wp{sp}; if(!wp.expired()) { SharedPtr<int> sp2 = wp.lock(); // Use sp2... }
-
实现
reset()函数,删除原有指针并分配nullptr给它:WeakPtr<int> wp{sp}; wp.reset(); // wp no longer references anything
-
实现
swap()函数,交换两个weak_ptr对象:WeakPtr<int> wp1{sp1}, wp2{sp2}; wp1.swap(wp2); // wp1 now watches sp2's object, wp2 watches sp1's
- 请事先阅读下发的材料,里面包含了绝大多数本次大作业当中需要用到的知识点,以及对三种智能指针功能的简要介绍,能够对本次大作业的背景有一个初步的了解;
- 开始写代码前一定要先进行程序设计,思考应当以什么结构框架实现各种功能,以避免不必要的代码堆砌或整体重构 (尤其是
shared_ptr与weak_ptr) - 注意函数实现中的细节,譬如
const、noexpect、explicit等(这些请自行查询资料了解),有时需要将这些关键词添加到适当函数处使智能指针可以正常运行,并且注意这些都有可能成为Code Review中考察的对象。
以下挑战完全是可选的,不会被测试或评分:
-
为整个项目添加线程安全相关的内容
-
支持数组并使其与自定义删除器兼容。例如:
void test10(double& score) { // test weak_ptr with arrays sharedptr<int[]> sp1{new int[5]{1, 2, 3, 4, 5}}; weakptr<int[]> wp1(sp1); // test that after move, the moved-from weak_ptr is expired weakptr<int[]> wp2(std::move(wp1)); // a moved-from weak_ptr should be expired if (!wp1.expired()) { result = false; return; } // test that the moved-to weak_ptr works correctly sharedptr<int[]> sp2 = wp2.lock(); if (!sp2 || sp2[0] != 1 || sp2[1] != 2) { result = false; return; } sp1.reset(); wp2.reset(); // need to reset wp2 explicitly if (wp2.lock()) { result = false; return; } score += 0.055; }
-
添加
owner_before()成员函数以实现关联容器中的一致排序。 -
在
if条件中使用自定义智能指针。如果智能指针包含nullptr,则该条件返回false否则返回true。UniquePtr<double> ptr{new double{1.567}}; if(ptr) // => true // something ptr.reset(); if(ptr) // => false // some other thing
使其对 UniquePtr, SharedPtr and WeakPtr 都生效.
本项目需要自行构建样例的 cpp 文件用以调试,善用 valgrind,这会有所帮助。
请各位自行测试无误后将对应的 hpp 文件提交到 ACMOJ 对应渠道即可.
特别感谢 Amirkabir University of Technology 1400-2 —— Advanced Programming Course Project 4 'Smart Pointers' .
感谢 2022 级汪畋宇学长创建了这个项目。
如有问题请联系本项目的发布者 duanzeqian, 他的邮箱地址是: tonyduan@sjtu.edu.cn。