C Связанное назначение перемещения списка и конструктор перемещения

#c #constructor #linked-list #nodes

#c #конструктор #связанный список #узлы

Вопрос:

Я пишу реализацию односвязного списка для моего класса объектно-ориентированного программирования. В программе я написал класс с именем Polynomial , который реализует связанный список и позволяет мне изменять его. Узлы в связанном списке содержат два поля: термин и указатель на следующий узел. Термин представляет собой структуру, содержащую два поля: коэффициент и показатель степени.

До этого момента я правильно реализовал класс и его методы, но я сталкиваюсь с проблемой в проекте, с которой мне нужна помощь. Одним из требований является то, что мы реализуем назначение перемещения (?) и конструктор перемещения. К сожалению, наш учитель не вдавался в подробности о том, что это такое и как их реализовать, и теперь я полностью запутался. Я уже реализовал назначение копирования и конструктор копирования, но я не знаю, как реализовать назначение перемещения и конструктор перемещения.

Вот такой класс:

 class Polynomial {
        Node* Head;
        int size = 0;
    public:
        Polynomial(); // default constructor
        Polynomial(const Polynomialamp; v); // copy constructor
        ~Polynomial();
        void addTerm(Term term);
        unsigned int degree() const;
        double coefficientFor(unsigned int exponent) const;
        void clear();

        // Copy Assignment Operator
        Polynomialamp; operator=(const Polynomialamp; rhs);

    private:
        void DeleteInvalidNode();
    };
 

Есть ли какой-нибудь способ, чтобы кто-нибудь мог помочь мне с этой реализацией и какова ее цель?

Ответ №1:

Допустим, вы хотите скопировать многочлен из одного места в другое. Например, вы можете захотеть написать метод, который позволяет нам приводить многочлен к некоторой степени. (Предположим, вы уже написали перегрузку оператора умножения). Это может выглядеть так [1]

 Polynomial Polynomial::pow(int n) const
{
  Polynomial result = *this; // copy constructor

  for(int i = 2; i < n; i  ) { result = result * *this; }

  return resu< 
}
 

Важно, чтобы вы делали копию *this , когда вы назначаете ее result в первой строке, потому что в противном случае вы можете изменять *this , когда пытаетесь изменить result .

С другой стороны, предположим, что вы позже используете этот метод следующим образом [2]:

 Polynomial s;

// ...

s = p.pow(3); // move-assignment
 

Результатом p.pow(3) является многочлен, но здесь нет необходимости сохранять s и p.pow(3) как отдельные объекты, потому что у нас нет возможности ссылаться на объект, на который ссылается as p.pow(3) , в любой дальнейшей точке кода.

Следовательно, нам не нужно быть осторожными при создании копии здесь; если есть какой-то способ, которым мы можем перенести возвращаемый объект p.pow(3) , не копируя тщательно каждую его часть, тогда все в порядке.

Мы объявляем этот метод следующим образом:

 class Polynomial
{
  // ...

  /** Move constructor */
  Polynomial(Polynomial amp;amp;);

  /** Move-assignment operator */
  Polynomialamp; operator=(Polynomial amp;amp;);

};
 

В этом случае, поскольку ваш многочлен представлен связанным списком, достаточно скопировать Head указатель, а затем сделать все, что вам нужно, с объектом, который вы перемещаете, чтобы убедиться, что его деструктор не уничтожает узлы связанного списка. Это будет зависеть от того, как вы все написали, но, вероятно, вам сойдет с рук что-то вроде установки Head указателя на объект, на который вы переместились nullptr .

(Конечно, помните, когда пишете оператор присваивания, чтобы очистить все, что нуждается в очистке в LHS!)

После того, как вы переместите-создаете или переместите-присваиваете из чего-либо, объект, из которого вы переместили, разрешается оставить в состоянии, при котором ни одна из его функций не обязательно работает, кроме деструктора; он не предназначен для дальнейшего использования. Например, в приведенном выше примере, где s = p.pow(3) , если у многочленов есть оператор присваивания перемещения, он будет вызван для перемещения возвращаемого значения s , а затем для возвращаемого значения будет вызван деструктор.


[1] На самом деле это не лучший способ написать этот метод, но он дает мне быстрый и несколько релевантный пример, поэтому я собираюсь использовать его.

[2] Здесь есть небольшая тонкость, объясняющая, почему я написал это как две отдельные строки. Если бы я должен был написать Polynomial s = p.pow(3) , это фактически обошло бы все это с помощью копирования, в основном указывая Polynomial::pow на использование s в качестве возвращаемого значения напрямую. Копирование и перемещение присваивания действительно используются только в том случае, если вы присваиваете что-то, что ранее имело другое значение.