唯一指针和双列表:插入问题

问题描述

我正在尝试按照 Stroustrup 的书“使用 C++ 的原则和实践”,第 20.4 章实现模板化双链表。我想使用唯一指针,而不是原始指针。 代码组织如下:

  • 实现结构体 Node 的头文件 Node.h
  • header Iterator.h,其中实现了 Iterator
  • header List.h,其中实现了类 List
  • 测试方法的 main.cpp

特别是,我目前对 iterator insert(iterator p,const T& x) 方法的实现感兴趣,该方法x 插入列表中的 p 之后。它可以编译,但是当我运行它时,我可以看到插入正确执行,然后出现分段错误,我坚信这是因为我在使用唯一指针时犯了一些错误。下面是insert方法的实现

    iterator insert(iterator position,const T& value) {
        auto newNode = new Node::Node<T>(value,position.current->next.get(),position.current);
        if (position.current == last ) {
            last.reset(newNode);
        }
    
        position.current->next.release(); 
        position.current->next.reset(newNode);
        ++_size;
        return position;
    }

为了方便起见,我把其他文件也写在这里

这是我的 Node.h

    #ifndef Node_h
    #define Node_h
    
    #include <algorithm>
    #include <iostream>
    #include <memory>  // std::unique_ptr
    #include <utility> // std::move
    
    
    
    namespace Node {
    
    
    template <typename T>
    struct Node {
        T data;
        std::unique_ptr<Node> next;
        Node* prevIoUs;
        
        Node() noexcept = default;
        explicit Node(const T& _data) : data{_data},next{nullptr},prevIoUs{nullptr} {
            std::cout << "l-value"<<std::endl;
        }
        Node(const T& _data,Node* _next,Node* _prevIoUs): data{_data},next{_next},prevIoUs{_prevIoUs} {}
    
        explicit Node(T&& x) : data{std::move(x)} {
          std::cout << "r-value" << std::endl;
        }
        
        Node(T&& x,Node* _prevIoUs) : data{std::move(x)},prevIoUs{_prevIoUs} {
          std::cout << "r-value" << std::endl;
        }
        
        explicit Node(const std::unique_ptr<Node> &x) : data{x->data} {
            if (x->next){
            next.reset(new Node{x->next});
            }
    //        if (x->prevIoUs){
    //            prevIoUs.reset(new Node{x->prevIoUs});
    //        }
        }
        
        
        
        ~Node()=default;
        
        //Move semantics,copy semantics
        
        void printNode(){
            std::cout << "Data is: " << data <<"\n";
        }
        
     };
    
    } //end namespace

    #endif /* Node_h */

然后,这是 Iterator.h

#ifndef Iterator_h
#define Iterator_h

#include "Node.h"
#include <iterator>

template <typename T >
struct __iterator {;
    using NodeT = Node::Node<T>;
    NodeT* current;
    
//public:
    using value_type = T;
    using difference_type = std::ptrdiff_t;
    using iterator_category = std::forward_iterator_tag;
    using reference = value_type&;
    using pointer = value_type *;
    
    explicit __iterator(NodeT* p) : current{p} {}
    __iterator() noexcept=default;
    ~__iterator()=default;
    
    reference operator*() const noexcept{
        return current->data;
    }
    
    pointer operator->() const noexcept{
        return &**this;
    }
    
    __iterator& operator++() {
      current = current->next.get();
      return *this;
    }
    
    __iterator& operator--(){
        current=current->prevIoUs; //prevIoUs is just a raw pointer
        return *this;
    }
    
    
    
    friend bool operator==(__iterator &a,__iterator &b) {
      return a.current == b.current;
    }
    

    friend bool operator!=(__iterator &a,__iterator &b) { return !(a == b); }
};

#endif /* Iterator_h */

这是标题 List.h

#include "Iterator.h"
#include <cassert>

template <typename T>
class List {
private:
    std::unique_ptr<Node::Node<T>> first;
    std::unique_ptr<Node::Node<T>> last;
    int _size;
public:
    
    
    using iterator = __iterator<T>;
    
    iterator begin(){return iterator{first.get()};}
    iterator end(){return iterator{nullptr};} //one past the last
    
    iterator go_to(const int n){
        assert(n>=0);
        int i=0;
        if (n < _size) {
            auto tmp{begin()};
            while (i<n) {
                ++tmp;
                ++i;
            }
            return tmp;
        }else{
            return iterator{nullptr};
        }
    }

    List() : first{nullptr},last{nullptr},_size{0} {}
    ~List() noexcept = default;
    
    
    template <typename O>
    void push_front(O &&x) { // forwarding ref. not r-value

        first.reset(new Node::Node<T>{std::forward<O>(x),first.release(),nullptr});
        if (_size==0) {
            last.reset(nullptr);
        }
        
        ++_size;
    }
    
    template <typename O> //forward reference
    void push_back(O&& x){
        auto tmp = first.get();
        auto _node = new Node::Node<T>{std::forward<O>(x)};
        if (!tmp) {
            first.reset(_node);
            return;
        }

        while (tmp->next) {
            tmp = tmp->next.get();
        }
        tmp->next.reset(_node);
        ++_size;
    }
    
    
    iterator substitute(iterator p,const T& x){
        //_size must not be incremented!
        iterator tmp{p};
        if(tmp.current){
            *tmp = x;
            return tmp;
        }else{
            return iterator{nullptr};
        }

    }
    
    iterator insert(iterator position,position.current);
        std::cout << position.current << std::endl;
        if (position.current == last.get() ) {
            last.reset(newNode);
        }
        
        position.current->next.release(); //otherwise: "pointer being freed was not allocated"
        position.current->next.reset(newNode); //set next of prevIoUs node to newNode
        ++_size;
        return position;
    }
    

    

    
    friend std::ostream& operator<<(std::ostream& os,List& l){
        auto itStop = l.end();
        os << "The list has " << l._size << " elements"<<"\n";
        for (auto it = l.begin(); it!=itStop; ++it) {
            os<< *it << " ";
        }
        return os;
    }
    
};

最后,这是包含测试的 main.cpp 文件

#include "List.h"

int main() {

    
    List<int> l{};

    int i=8;
    l.push_front(i); //l-value
    l.push_back(4); //r-value
    l.push_back(i+2); //r-value
    l.push_back(95); //r-value
    l.push_front(29); //l-value
    l.push_front(i*i); //r-value
    std::cout << "My list so far: " << l<<std::endl;

    auto p{l.go_to(3)};
    auto itt = l.substitute(p,29);
    std::cout << "My list after substitution: \t" << l<<std::endl;

    auto pp{l.go_to(2)};
    auto it2 = l.insert(pp,98);
    std::cout << "My list after insertion: \t" << l<<std::endl;
    auto it3= l.insert(--pp,998);
    std::cout << "My list after insertion: \t" << l<<std::endl;
    
    return 0;
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)