Skip to content

About

For SJTU CS1958-01 2026Fall Project2

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

Project 2: $\mathrm{Smart Pointer}$

SJTU CS1958-01 2026Fall 第二次大作业

开始项目前,建议先阅读智能指针:从入门到入土

本项目要实现的内容是一个类模板,可能有类似于template <typename T>的语句,你可以在理解的时候将T视作某一种特殊的类型名称(或者视为int)。根据这一规则,被包装的原始指针的类型就是T*。

Unique_ptr

你需要构造的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()函数,包括以下两种参数形式:

    1. void reset() 删除原有指针并分配 nullptr 给它
    2. 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

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() 函数,包括实现以下两种参数形式:

    1. void reset() 删除原有指针并分配 nullptr 给它
    2. 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

为此,你需要构造的 weak_ptr 模版类的要求包括:

  • 默认构造函数,内部指针默认应当为nullptr:

    WeakPtr<int> wp;
  • 能够支持将 shared_ptr 转换成 weak_ptr 的构造函数:

    SharedPtr<int> sp{new int{10}};
    WeakPtr<int> wp{sp};
  • 移动构造函数与拷贝构造函数,注意在拷贝构造中可以通过 shared_ptr 构造 weak_ptr

    WeakPtr<int> wp1{sp};
    WeakPtr<int> wp2{wp1};             // compile success
    WeakPtr<int> wp2{std::move(wp1)};  // compile success
  • 拥有析构函数 ~WeakPtr() 删除动态指针并将其置为 nullptr

  • 重载运算符 operator=,实现移动赋值与拷贝赋值,注意在拷贝赋值中可以将 shared_ptr 赋给 weak_ptr

    WeakPtr<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

注意事项

  1. 请事先阅读下发的材料,里面包含了绝大多数本次大作业当中需要用到的知识点,以及对三种智能指针功能的简要介绍,能够对本次大作业的背景有一个初步的了解;
  2. 开始写代码前一定要先进行程序设计,思考应当以什么结构框架实现各种功能,以避免不必要的代码堆砌或整体重构 (尤其是shared_ptr与weak_ptr)
  3. 注意函数实现中的细节,譬如 const、noexpect、explicit等(这些请自行查询资料了解),有时需要将这些关键词添加到适当函数处使智能指针可以正常运行,并且注意这些都有可能成为Code Review 中考察的对象。

Bonus

以下挑战完全是可选的,不会被测试或评分:

  • 为整个项目添加线程安全相关的内容

  • 支持数组并使其与自定义删除器兼容。例如:

    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 对应渠道即可.

评分规则

Acknowledgement

特别感谢 Amirkabir University of Technology 1400-2 —— Advanced Programming Course Project 4 'Smart Pointers' .

感谢 2022 级汪畋宇学长创建了这个项目。

如有问题请联系本项目的发布者 duanzeqian, 他的邮箱地址是: tonyduan@sjtu.edu.cn。

About

For SJTU CS1958-01 2026Fall Project2

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages