复制构造函数在向堆栈中插入元素时出现的故障

问题描述 投票:0回答:1

在我的.h文件中,我得到了一个Node和Stack类。我必须在不同的测试文件中实现复制构造函数、赋值操作符和破坏构造函数并进行测试。当测试复制构造函数时,在插入3个元素后,它只显示一个元素。我不知道哪里出了问题,这是我的.h文件,供大家参考。

#ifndef _STACK_H
#define _STACK_H
#include <iostream>
#include <exception>
using std::ostream;
using std::cout;
using std::endl;
using std::range_error;
// Forward declarations
template <class T> class Stack;
template <class T> class Node;
template <class T> ostream& operator<<(ostream&, const Node<T>&);

// Node class for linked list
template <class T>
class Node {
    friend Stack<T>;
public:
    Node(T data = T(), Node<T>* next = nullptr) {
        _data = data;
        _next = next;
    }
    friend ostream& operator<< <T>(ostream& sout, const Node<T>& x);
private:
    T _data;
    Node* _next;
};
// Overloaded insertion operator.  Must be overloaded for the template
// class T, or this won't work!
template <class T>
ostream& operator<<(ostream& sout, const Node<T>& x) {
    sout << "Data: " << x._data;
    return sout;
}

// Stack class.  Linked-list implementation of a stack. Uses the Node
// class.
template <class T>
class Stack {
public:
    // Constructor
    Stack();

    // Copy constructor, assignment operator, and destructor
    // DO NOT IMPLEMENT HERE.  SEE BELOW.
    Stack(const Stack& rhs);
    const Stack& operator=(const Stack& rhs);
    ~Stack();

    void push(const T& data);
    const T& top() const;
    void pop();
    bool empty() const;  // Returns 'true' if stack is empty
    void dump() const;

    //Delete method used for destructor
    void nullify();

private:
    Node<T>* _head;
    Node<T>* _temp1;
    Node<T>* _temp2; //pointers
};

template <class T>
Stack<T>::Stack() {
    _head = nullptr;
}

template <class T>
Stack<T>::Stack(const Stack<T>& rhs) {
    if (rhs._head != nullptr) {
        _head = new Node<T>(rhs._head->_data);
        _temp1 = _head->_next;  //temp1 would be the next one after head
        //_temp2 = _temp2->_next; 
        while (_temp2 != nullptr) {
            _temp1 = new Node<T>(_temp2->_data);
            _temp1 = _temp1->_next;
            _temp2 = _temp2->_next; //temp2 should be the next node after temp1
        }
    }
    else
        _head = nullptr;
}

template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
    if (this != &rhs) {
        nullify();
        if (rhs._head != nullptr) {
            _head = new Node<T>(rhs._head->_data);
            _temp1 = _head->_next;  //temp1 would be the next one after head
            //_temp2 = _temp2->_next; 

            while (_temp2 != nullptr) {
                _temp1 = new Node<T>(_temp2->_data);
                _temp1 = _temp1->_next;
                _temp2 = _temp2->_next; //temp2 should be the next node after temp1
            }
        }
        else
            _head = nullptr;
    }
    return *this;
}

template <class T>
Stack<T>::~Stack() {
    nullify();
}

template <class T>
void Stack<T>::nullify() {
    while (!empty()) {
        pop();
    }
}

template <class T>
void Stack<T>::pop() {
    if (empty()) {
        throw range_error("Stack<T>::pop(): attempt to pop from an empty stack.");
    }

    Node<T>* tmpPtr = _head->_next;
    delete _head;
    _head = tmpPtr;
}

template <class T>
bool Stack<T>::empty() const {
    return _head == nullptr;
}

template <class T>
void Stack<T>::push(const T& data) {
    Node<T>* tmpPtr = new Node<T>(data);
    tmpPtr->_next = _head;
    _head = tmpPtr;
}

template <class T>
const T& Stack<T>::top() const {
    if (empty()) {
        throw range_error("Stack<T>::top(): attempt to read empty stack.");
    }

    return _head->_data;
}

template <class T>
void Stack<T>::dump() const {
    Node<T>* nodePtr = _head;
    while (nodePtr != nullptr) {
        cout << nodePtr->_data << endl;
        nodePtr = nodePtr->_next;
    }
}
#endif

当推送34, 67, 92时,在输出过程中,复制构造函数只显示92。 这是我测试我的.h代码的代码。

#include "stack.h"
#include <iostream>
using namespace std;
using std::cout;
using std::endl;

int main()
{
    cout << "Testing default constructor\n";

    Stack<int> intStack;

    intStack.dump();
    cout << "Stack is empty initially\n\n";

    intStack.push(34);
    intStack.push(67);
    intStack.push(92);

    cout << "Testing copy constructor after inserting 92, 67 & 34: \n";
    Stack<int> test1(intStack);
    //cout << "Dumping intStack into Test1 & displaying it: \n";
    test1.dump();

    cout << "\nTesting destructor: \n";
    test1.nullify();
    test1.dump();
    cout << "Its empty\n\n";

    Stack<int> test2;

    test2.push(75);
    test2.push(56);
    test2.push(88);
    test2.push(69);

    cout << "Testing assignment operator after inserting 69, 88, 56 & 75: \n";

    Stack<int> test3;

    test3 = test2;
    test3.dump();

    cout << "\nTesting destructor: \n";
    test2.nullify();
    test2.dump();
    cout << "Its empty\n\n";

    return 0;
}

我还没有完全学会C++,所以有任何错误都很抱歉。

c++ stack copy-constructor
1个回答
2
投票

有几个问题,你的 Stack 类。

首先,复制构造函数没有初始化所有成员,你的默认构造函数也没有初始化。 这些都需要修正。

template <class T>
Stack<T>::Stack() : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {}

template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr)
{
  //...
}

一旦这些都解决了,复制构造函数就可以很容易地用你现有的其他函数来实现了。Stack::push. 你的实现太复杂了。

template <class T>
Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
    Node<T>* temp = rhs._head;
    while (temp)
    {
        push(temp->_data);
        temp = temp->_next;
    }
}

这里做的是什么? 很简单 -- 我们所做的只是把传入的头部的 Stack的项目,并循环调用 Stack::push 将数据添加到新的 Stack 对象。 由于你有一个 push 函数已经编好了,你应该使用它。

第二,注意我们使用了一个本地的 temp 变量。 我怀疑你是否需要这些 _temp 的成员,但这是另一回事。

最后,你的赋值操作符可以很容易地实现,因为你有一个复制构造函数和destructor,用于在类中的 Stack:

template <class T>
const Stack<T>& Stack<T>::operator=(const Stack<T>& rhs) {
    if (this != &rhs) {
        Stack<T> temp = rhs;
        std::swap(temp._head, _head);
        std::swap(temp._temp1, _temp1);
        std::swap(temp._temp2, _temp2);
    }
    return *this;
}

该技术使用 互换. 所有正在做的事情就是从传入的一个临时的 Stack 对象,然后把当前的内容和临时的内容换掉。 然后临时的内容和旧的内容一起消亡。

考虑到这一切,这个类应该可以正常工作。 至于是否100%正确地使用其他所有功能,那又是另一个问题了。

编辑。

这里是对复制构造函数的修正。 注意,我们仍然使用现有的函数来进行复制。

  template <class T>
    Stack<T>::Stack(const Stack<T>& rhs) : _head(nullptr), _temp1(nullptr), _temp2(nullptr) {
        Node<T>* temp = rhs._head;
        Stack<T> tempStack;
        while (temp)
        {
            tempStack.push(temp->_data);
            temp = temp->_next;
        }
        while (!tempStack.empty())
        {
           push(tempStack.top()); 
           tempStack.pop();
        }
    }

这样做效率不高 但通常堆栈数据结构会使用一个底层容器,比如: vector 其中,很容易反转底层内容,而不是像你使用的那样基于单一的link-list。

© www.soinside.com 2019 - 2024. All rights reserved.