Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在链表中移动和复制构造函数_C++_Copy Constructor_Doubly Linked List_Class Design_Move Constructor - Fatal编程技术网

C++ 在链表中移动和复制构造函数

C++ 在链表中移动和复制构造函数,c++,copy-constructor,doubly-linked-list,class-design,move-constructor,C++,Copy Constructor,Doubly Linked List,Class Design,Move Constructor,我仍在努力学习有关复制和移动构造函数的更多信息。我有一个链表类,我想使用复制和移动构造函数进行深度复制,但我遇到了一些问题。首先,对于深度复制列表类,我只复制构造函数中的head和tail。我知道代码很可怕,也许我不应该马上跳进高级的东西 感谢您的帮助 样板 班级名单 { 公众: 类节点{ 公众: 节点集值:值\值{} T值; 节点*下一个节点; 节点*上一个节点; }; 节点*头; 节点*tail\ux; //!默认构造函数 列表:tail_nullptr{} //!复制构造函数 Listco

我仍在努力学习有关复制和移动构造函数的更多信息。我有一个链表类,我想使用复制和移动构造函数进行深度复制,但我遇到了一些问题。首先,对于深度复制列表类,我只复制构造函数中的head和tail。我知道代码很可怕,也许我不应该马上跳进高级的东西

感谢您的帮助

样板 班级名单 { 公众: 类节点{ 公众: 节点集值:值\值{} T值; 节点*下一个节点; 节点*上一个节点; }; 节点*头; 节点*tail\ux; //!默认构造函数 列表:tail_nullptr{} //!复制构造函数 Listconst List&lst:头\u空PTR{ //不知道这里有什么 } } //! 移动构造函数 列表移动(&M){ 头部=移动。头部; move.head=空ptr; tail=move.tail; move.tail=nullptr; } //! 复制赋值运算符 列表和运算符=常量列表和列表{ 尾部=空PTR; 头=尾; 节点*当前=列表头; Node*next=list.head->next; 节点*replace=头部*; 而下一步!=list.tail\u{ 当前=当前->下一步; 下一步=下一步->下一步; 替换->下一步=尾部; 替换->下一步->值; 替换=替换->下一步; } 归还*这个; } //! 移动赋值运算符 列表和运算符=列表和其他{ 尾部=空PTR; 头=尾; head->next=其他。head->next; 节点*当前=other.head\ux; Node*next=other.head->next; 而下一个!=另一个.tail\u{ 当前=当前->下一步; 下一步=下一步->下一步; } 当前->下一步=尾部; other.head->next=other.tail; 归还*这个; } 因为List跟踪尾部,所以您可以调用一个函数,将项目添加到列表的末尾,而无需增加迭代到列表末尾的开销

List(const List& lst) : head_(nullptr), tail_(nullptr) 
{
    Node * cur = lst.head_; //get first source item.
    while (cur) // if there is a source item to copy
    {
        push_back(cur->value_); // stick the item on the end of this list
        cur = cur->next_; // get next source item
    }
}
推回看起来像

void push_back(T value)
{
    Node * newnode = new Node(value, tail_, nullptr); //make and link new tail node

    if (tail_)
    {
        tail_->next_ = newnode; // link in new node
    }
    else
    {
         head_ = newnode;
    }
    tail_ = newnode; // update tail
}
Node选择了一个新的构造函数来简化插入:

Node(T value, 
     Node * prev, 
     Node * next) : value_(value), prev_(prev), next_(next) 
{
}
注: 在赋值运算符中

tail_ = nullptr;
head_ = tail_;
切断指向链接列表中任何数据的指针,从而泄漏这些节点。在替换这些节点之前,需要释放它们。“复制和交换”习惯用法通过使用局部变量的复制构造和销毁来自动化该过程,从而简化了这一过程。

因为列表跟踪尾部,所以您可以调用一个函数,将项目添加到列表的末尾,而无需增加迭代到列表末尾的开销

List(const List& lst) : head_(nullptr), tail_(nullptr) 
{
    Node * cur = lst.head_; //get first source item.
    while (cur) // if there is a source item to copy
    {
        push_back(cur->value_); // stick the item on the end of this list
        cur = cur->next_; // get next source item
    }
}
推回看起来像

void push_back(T value)
{
    Node * newnode = new Node(value, tail_, nullptr); //make and link new tail node

    if (tail_)
    {
        tail_->next_ = newnode; // link in new node
    }
    else
    {
         head_ = newnode;
    }
    tail_ = newnode; // update tail
}
Node选择了一个新的构造函数来简化插入:

Node(T value, 
     Node * prev, 
     Node * next) : value_(value), prev_(prev), next_(next) 
{
}
注: 在赋值运算符中

tail_ = nullptr;
head_ = tail_;

切断指向链接列表中任何数据的指针,从而泄漏这些节点。在替换这些节点之前,需要释放它们。复制和交换习惯用法通过使用局部变量的复制构造和销毁来自动化过程,使这一过程变得容易。

这是我的五分钱:

下面的演示程序显示了如何实现复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符和析构函数,包括一些其他辅助函数

#include <iostream>
#include <utility>
#include <functional>
#include <iterator>

template<typename T>
class List
{
private:
    struct Node 
    {
        T value;
        Node *prev;
        Node *next;
    } *head = nullptr, *tail = nullptr;

    void copy( const List &list )
    {
        if ( list.head )
        {
            head = tail = new Node { list.head->value, nullptr, nullptr };

            for ( Node *current = list.head->next; current; current = current->next )
            {
                tail = tail->next = new Node { current->value, tail, nullptr };             
            }
        }           
    }
    
public:
    //! Default constructor
    List() = default;

    //! Copy constructor
    List( const List &list )
    {
        copy( list );
    }

    //  Constructor with iterators
    template <typename InputIterator>
    List( InputIterator first, InputIterator last )
    {
        if ( first != last )
        {
            head = tail = new Node { *first, nullptr, nullptr };

            while ( ++first != last )
            {
                tail = tail->next = new Node { *first, tail, nullptr };             
            }
        }
    }

    //  Destructor
    ~List()
    {
        clear();
    }
    
    //! Move constructor
    List( List &&list ) 
    {
        std::swap( head, list.head );
        std::swap( tail, list.tail );
    }

    //! Copy assignment operator
    List & operator =( const List &list ) 
    {
        clear();
        copy( list );
        
        return *this;
    }
    
    //! Move assignment operator
    List & operator =( List &&list ) 
    {
        std::swap( head, list.head );
        std::swap( tail, list.tail );
        
        return *this;
    }
    
    void clear()
    {
        while ( head )
        {
            delete std::exchange( head, head->next );
        }
        
        tail = head;
    }
    
    void push_front( const T &value )
    {
        head = new Node{ value, nullptr, head };

        if ( !tail )
        {
            tail = head;
        }
        else
        {
            head->next->prev = head;
        }
    }

    void push_back( const T &value )
    {
        Node *new_node = new Node{ value, tail, nullptr };

        if ( tail )
        {
            tail = tail->next = new_node;
        }
        else
        {
            head = tail = new_node;
        }
    }
    
    friend std::ostream & operator <<( std::ostream &os, const List &list )
    {
        for ( Node *current = list.head; current; current = current->next )
        {
            os << current->value << " -> ";
        }
        
        return os << "null";
    }
};

int main()
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
    List<int> list1( std::begin( a ), std::end( a ) );
    
    std::cout << list1 << '\n';
    
    list1 = List<int>( std::rbegin( a ), std::rend( a ) );

    std::cout << list1 << '\n';
    
} 
例如在这句话中

list1 = List<int>( std::rbegin( a ), std::rend( a ) );

这里使用了移动分配运算符。

这是我的五美分:

下面的演示程序显示了如何实现复制构造函数、移动构造函数、复制赋值运算符、移动赋值运算符和析构函数,包括一些其他辅助函数

#include <iostream>
#include <utility>
#include <functional>
#include <iterator>

template<typename T>
class List
{
private:
    struct Node 
    {
        T value;
        Node *prev;
        Node *next;
    } *head = nullptr, *tail = nullptr;

    void copy( const List &list )
    {
        if ( list.head )
        {
            head = tail = new Node { list.head->value, nullptr, nullptr };

            for ( Node *current = list.head->next; current; current = current->next )
            {
                tail = tail->next = new Node { current->value, tail, nullptr };             
            }
        }           
    }
    
public:
    //! Default constructor
    List() = default;

    //! Copy constructor
    List( const List &list )
    {
        copy( list );
    }

    //  Constructor with iterators
    template <typename InputIterator>
    List( InputIterator first, InputIterator last )
    {
        if ( first != last )
        {
            head = tail = new Node { *first, nullptr, nullptr };

            while ( ++first != last )
            {
                tail = tail->next = new Node { *first, tail, nullptr };             
            }
        }
    }

    //  Destructor
    ~List()
    {
        clear();
    }
    
    //! Move constructor
    List( List &&list ) 
    {
        std::swap( head, list.head );
        std::swap( tail, list.tail );
    }

    //! Copy assignment operator
    List & operator =( const List &list ) 
    {
        clear();
        copy( list );
        
        return *this;
    }
    
    //! Move assignment operator
    List & operator =( List &&list ) 
    {
        std::swap( head, list.head );
        std::swap( tail, list.tail );
        
        return *this;
    }
    
    void clear()
    {
        while ( head )
        {
            delete std::exchange( head, head->next );
        }
        
        tail = head;
    }
    
    void push_front( const T &value )
    {
        head = new Node{ value, nullptr, head };

        if ( !tail )
        {
            tail = head;
        }
        else
        {
            head->next->prev = head;
        }
    }

    void push_back( const T &value )
    {
        Node *new_node = new Node{ value, tail, nullptr };

        if ( tail )
        {
            tail = tail->next = new_node;
        }
        else
        {
            head = tail = new_node;
        }
    }
    
    friend std::ostream & operator <<( std::ostream &os, const List &list )
    {
        for ( Node *current = list.head; current; current = current->next )
        {
            os << current->value << " -> ";
        }
        
        return os << "null";
    }
};

int main()
{
    int a[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    
    List<int> list1( std::begin( a ), std::end( a ) );
    
    std::cout << list1 << '\n';
    
    list1 = List<int>( std::rbegin( a ), std::rend( a ) );

    std::cout << list1 << '\n';
    
} 
例如在这句话中

list1 = List<int>( std::rbegin( a ), std::rend( a ) );

这里使用了移动分配操作符。

//不确定这里是什么-如果没有公共成员函数将项目添加到列表中,您如何能够测试您的类?另外,复制构造函数和析构函数应该是您要编写的前两个函数,我想我不会把它包含在代码中,但是我确实有链表的插入成员/不确定这里有什么东西-考虑把你在赋值运算符中的所有代码移放到那里,边注:如果你先复制并移动构造函数,您可以利用并使赋值运算符非常简单;头=尾;泄漏了列表中的任何内容//不确定这里包含什么-如果没有公共成员函数向列表中添加项,您如何能够测试您的类?另外,复制构造函数和析构函数应该是您要编写的前两个函数,我想我不会把它包含在代码中,但是我确实有链表的插入成员/不确定这里有什么东西-考虑移动你在赋值操作符中的所有代码并放置它。
e、 旁注:如果您首先执行复制和移动构造函数,则可以利用,并使赋值运算符非常简单;头=尾;泄漏了列表中的任何内容。谢谢,这是有意义的,所以现在如果我想重载复制分配操作符,它看起来会像这样吗?List&operator=const List&List\u copy{List tmplist\u copy;return*this;}@user4581301如果列表为空,则您的推送操作不会更新头。我自己刚刚发现了这一点。谢谢你,雷米。@Hazemenaceur-你忘了把tmp成员和*的成员交换。这就是为什么这种技术被称为复制和交换。@Hazemenaceur分配还有一个问题,即列表中可能已经包含了必须处理的数据。在遍历源列表并插入新节点之前,您可以遍历列表并删除所有现有节点,但我还是要推送复制和交换,因为它几乎像您在生活中得到的那样简单。谢谢,这很有意义,所以现在如果我想重载复制赋值操作符,看起来像这样?List&operator=const List&List\u copy{List tmplist\u copy;return*this;}@user4581301如果列表为空,则您的推送操作不会更新头。我自己刚刚发现了这一点。谢谢你,雷米。@Hazemenaceur-你忘了把tmp成员和*的成员交换。这就是为什么这种技术被称为复制和交换。@Hazemenaceur分配还有一个问题,即列表中可能已经包含了必须处理的数据。在遍历源列表并插入新节点之前,您可以遍历列表并删除所有现有节点,但我还是要推送复制和交换,因为它几乎和您在生活中得到的一样简单。这是五美分的规则吗?这是五美分的规则吗?