diff --git a/README.md b/README.md index 2735d0d..da73c9c 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,29 @@ ## 作业要求 -修改 main.cpp,改良其中的双链表类 `List`: - - 避免函数参数不必要的拷贝 5 分 + - `print()`和`push_front()`改为常量参数传递,避免拷贝 + - 修复智能指针造成的问题 10 分 + - `shared_ptr`循环引用造成内存无法释放 + - 改用 `unique_ptr` 10 分 - 实现拷贝构造函数为深拷贝 15 分 + - 使用迭代器遍历目标,开辟新内存并赋值 + - 说明为什么可以删除拷贝赋值函数 5 分 + - 编译器会自动创建一个纯右值,再用移动构造将所有权转给等号左边的变量,相当于调用了右值构造+移动赋值 + - 改进 `Node` 的构造函数 5 分 + - 声明为explicit,防止单参数隐式构造,初始列构造减少一次赋值 + +## 模板 + +List和Node类都实现为模板类,并用`List`测试成功 + +## 迭代器 -并通过 `main()` 函数中的基本测试。 +实现了`list_iterator`,拷贝构造时深拷贝的遍历操作使用迭代器完成 ## 关于内卷 diff --git a/main.cpp b/main.cpp index dc25c6b..f0ddc6e 100644 --- a/main.cpp +++ b/main.cpp @@ -2,118 +2,174 @@ #include #include -struct Node { - // 这两个指针会造成什么问题?请修复 - std::shared_ptr next; - std::shared_ptr prev; - // 如果能改成 unique_ptr 就更好了! - - int value; - - // 这个构造函数有什么可以改进的? - Node(int val) { - value = val; - } - - void insert(int val) { - auto node = std::make_shared(val); - node->next = next; - node->prev = prev; - if (prev) - prev->next = node; - if (next) - next->prev = node; - } - - void erase() { - if (prev) - prev->next = next; - if (next) - next->prev = prev; - } - - ~Node() { - printf("~Node()\n"); // 应输出多少次?为什么少了? - } +template +struct Node +{ + std::unique_ptr next; + Node* prev; + // 如果能改成 unique_ptr 就更好了! + + value_type value; + + // 这个构造函数有什么可以改进的?:防止单参数隐式构造,初始列构造减少一次赋值 + explicit Node(value_type val) : value(val) + {} + + void erase() { + if (next) + next->prev = prev; + if (prev) + prev->next = std::move(next); + } + + ~Node() { + printf("~Node() : %f\n", value); // 应输出多少次?为什么少了?:14次,share_ptr循环引用导致内存无法释放 + } }; -struct List { - std::shared_ptr head; - - List() = default; - - List(List const &other) { - printf("List 被拷贝!\n"); - head = other.head; // 这是浅拷贝! - // 请实现拷贝构造函数为 **深拷贝** - } - - List &operator=(List const &) = delete; // 为什么删除拷贝赋值函数也不出错? - - List(List &&) = default; - List &operator=(List &&) = default; - - Node *front() const { - return head.get(); - } - - int pop_front() { - int ret = head->value; - head = head->next; - return ret; - } - - void push_front(int value) { - auto node = std::make_shared(value); - node->next = head; - if (head) - head->prev = node; - head = node; - } - - Node *at(size_t index) const { - auto curr = front(); - for (size_t i = 0; i < index; i++) { - curr = curr->next.get(); - } - return curr; - } + +template +struct List +{ + using node_type = Node; + + class list_iterator + { + public: + using iterator_catagory = std::bidirectional_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = node_type; + using pointer = node_type*; + using reference = node_type&; + + list_iterator(pointer ptr) : m_ptr(ptr) + {} + + reference operator*() { return *m_ptr; } + pointer operator->() { return m_ptr; } + + list_iterator operator++() { + m_ptr = m_ptr->next.get(); + return *this; + } + + list_iterator operator++(int) { + return ++(*this); + } + + friend bool operator==(const list_iterator a, const list_iterator b) { + return a.m_ptr == b.m_ptr; + } + + friend bool operator!=(const list_iterator a, const list_iterator b) { + return a.m_ptr != b.m_ptr; + } + + private: + node_type* m_ptr; + }; + +public: + std::unique_ptr head; + node_type* back; + List() = default; + + List(List const& other) { + printf("List 被拷贝!\n"); + + // 请实现拷贝构造函数为 **深拷贝** + head = std::make_unique(other.cbegin()->value); + back = head.get(); + for (auto it = ++other.cbegin(); it != other.cend(); ++it) { + push_back(it->value); + } + } + + List& operator=(List const&) = delete; // 为什么删除拷贝赋值函数也不出错?:编译器自动创建一个纯右值,再用移动构造将所有权转给等号左边的变量 + + List(List&&) = default; + List& operator=(List&&) = default; + + node_type* front() const { + return head.get(); + } + + T pop_front() { + T ret = head->value; + head = std::move(head->next); + return ret; + } + + void push_front(const T& value) { + auto node = std::make_unique(value); + if (head) + head->prev = node.get(); + else + back = node.get(); + node->next = std::move(head); + head = std::move(node); + } + + void push_back(const T& value) { + auto node = std::make_unique(value); + node->prev = back; + back->next = std::move(node); + back = back->next.get(); + } + + node_type* at(size_t index) const { + auto curr = front(); + for (size_t i = 0; i < index; i++) { + curr = curr->next.get(); + } + return curr; + } + + list_iterator cbegin() const { return list_iterator(head.get()); } + + list_iterator cend() const { return list_iterator(nullptr); } + + //TODO:非const的begin(),end() + //TODO:shared_ptr改unique_ptr + //TODO:end(),back实现修改,返回值依然是nullptr,但可以-- }; -void print(List lst) { // 有什么值得改进的? - printf("["); - for (auto curr = lst.front(); curr; curr = curr->next.get()) { - printf(" %d", curr->value); - } - printf(" ]\n"); +template +void print(List const& lst) { + // 有什么值得改进的?:常量引用传递避免拷贝 + printf("["); + for (auto curr = lst.front(); curr; curr = curr->next.get()) { + printf(" %f", curr->value); + } + printf(" ]\n"); } int main() { - List a; + List a; - a.push_front(7); - a.push_front(5); - a.push_front(8); - a.push_front(2); - a.push_front(9); - a.push_front(4); - a.push_front(1); + a.push_front(7.2f); + a.push_front(5.5f); + a.push_front(8.2f); + a.push_front(2.1f); + a.push_front(9.3f); + a.push_front(4.5f); + a.push_front(1.9f); - print(a); // [ 1 4 9 2 8 5 7 ] + print(a); // [ 1 4 9 2 8 5 7 ] - a.at(2)->erase(); + a.at(2)->erase(); - print(a); // [ 1 4 2 8 5 7 ] + print(a); // [ 1 4 2 8 5 7 ] - List b = a; + List b = a; - a.at(3)->erase(); + a.at(3)->erase(); - print(a); // [ 1 4 2 5 7 ] - print(b); // [ 1 4 2 8 5 7 ] + print(a); // [ 1 4 2 5 7 ] + print(b); // [ 1 4 2 8 5 7 ] - b = {}; - a = {}; + b = {}; + a = {}; - return 0; + return 0; }