簡體   English   中英

在C ++中具有動態分配的單鏈接列表的賦值運算符(MS Visual Studio 2015)

[英]Assignment Operator for singly linked list with dynamic allocation in C++ (MS Visual Studio 2015)

兩類,一類用於節點,一類用於單鏈表。

// node class
template <typename T>
class Element{
private:

  Element *next_ = nullptr;
  string name_ = "";
  T color_ = T();

public:

  Element()=default;
  Element(string name, T d) : next_(nullptr), name_(name), color_(d){};

  friend ostream& operator<<(ostream& out, Element& n){

      out << n.name_ << ":" << n.color_;

      return out;
  }

  friend class PAL<T>;

};

/* "This is a singly linked list of Elements that, taken in order,
constitute the Painter's ALgorithm." */
template<typename T>
class PAL{

private:

  Element<T> *back_ = nullptr;
  Element<T> *front_ = nullptr;

  void print_list(ostream& out); 

public:

  PAL()=default;
  PAL(Element<T> n) : back_(&n), front_(&n) {};
  PAL(string n, T d);
  PAL(const PAL&);
  ~PAL();

  PAL& operator=(PAL);

  void add(Element<T> &n);
  void add(string name, T dat);

  pair<Element<T>*, Element<T>*> find(string name);    
  pair<Element<T>*, Element<T>*> find(Element<T> &n);

  void move_forward1(Element<T> &n);
  void move_to_front(Element<T> &n);  

  void move_back1(Element<T> &n);
  void move_to_back(Element<T> &n);  

  friend ostream& operator<<(ostream& out, PAL<T>& sl){
    sl.print_list(out);
    return out;
  }

現在,對於賦值運算符,我已經嘗試了兩件事。

template<typename T>
PAL<T> & PAL<T>::operator=(PAL p)
{
    front_ = p.front_;
    back_ = p.back_;

    return *this;
}

以及使用std :: swap的變體。 兩者都編譯,但是會給出運行時錯誤。

當我使用swap時,我會遇到一個錯誤,我認為該錯誤用完了內存?

表達式:“((_ Ptr_user&(_BIG_ALLOCATION_ALIGNMENT -1))== 0” && 0

如果我使用第一個,則沒有交換,發生奇怪的事情。 我經歷了調試過程,並觀察了“ this”和“ p”,因為它逐步執行了該功能,並且運行良好,直到最后,最后一個括號,無論暗示什么,突然間“ p”和“ this”都沒有改變只是對nullptrs,但對0xdddddd(我猜是d的數目)。 因此,它有各種各樣的問題。

我想知道為什么會發生這些事情,但是如果沒有其他事情,我需要知道我應該怎么做!

非常感謝。

編輯:該功能現在如下。

template<typename T>
PAL<T> & PAL<T>::operator=(const PAL &p)
{
    Element<T> *new_front = nullptr, *new_back = nullptr;
    Element<T> *address = p.back_;

    while (address != nullptr) {
        /* the add method in this loop will end up taking
         care of front_ and back_ too */

        add(address->name_, address->color_);
        pair<Element<T>*, Element<T>*> found = find(address->name_);
        if (new_front == nullptr) {
            new_front = found.first;
        }
        new_back = found.first;
        //move_to_front(*found.first);

        address = address->next_;
    }


    Element<T> *old = p.back_;
    while (old) {
        Element<T> *last = old;
        old = old->next_;
        delete last;
    }

    front_ = new_front;
    back_ = new_back;


    return *this;
}

注意,back_表示列表中的“第一個”項目(沒有指向它),而front_表示最后一個,它沒有指向任何內容。

復制分配操作員的工作不僅僅是復制指針。 默認的編譯器生成可以為您做到這一點。

該運算符的工作是將另一個對象的內容復制到一個完全獨立的對象中。 這意味着將每個Element<T>對象從另一個對象復制到該對象中。 這也意味着您必須處理銷毀當前對象包含的所有節點。

正如您所做的那樣,僅復制指針就意味着對一個PAL<T>更改很可能會在另一個中反映出來。 如果頭部或尾部發生變化,則只有一個PAL<T>會發生這種變化。

更糟糕的是,如果將一個PAL<T>復制分配給另一個PAL<T> ,則現在有兩個PAL<T>對象認為它們擁有它們包含的Element<T>對象。 然后,當兩者都銷毀時,它們各自將嘗試刪除這些對象。 這導致雙重釋放,從而導致未定義的行為。

首先,更改運算符以引用常量而不是副本。

然后,您將要使用的一般模式如下:

template<typename T>
PAL<T> & PAL<T>::operator=(const PAL &p)
{
    // Store the old list here, which we will deallocate at the end. This
    // step is necessary to do first in case some code copy-assigns an
    // instance to itself; since in that case it is copying its own data,
    // we can't deallocate it yet or we will just lose the data completely.
    Element<T> *old_back = back_;

    // Reset this instance.
    front_ = nullptr;
    back_ = nullptr;

    // Duplicate the elements of p, storing them in this object.
    // You will have to make sure the next_ fields of the new elements point
    // into the duplicated chain, not the original!
    //
    // Left as an exercise for you to implement.

    // Deallocate and free the nodes that were contained in this object.
    while (old_back) {
        Element<T> *last = old_back;
        old_back = old_back->next;
        delete last;
    }

    return *this;
}

我猜您的副本構造函數也不會執行此重復。 如果沒有,則可以根據此運算符來實現它,以最大程度地減少代碼重復:

template<typename T>
PAL<T>::PAL(const PAL &p) : front_(nullptr), back_(nullptr) {
    *this = p;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM