#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
в качестве возвращаемого значения напрямую. Копирование и перемещение присваивания действительно используются только в том случае, если вы присваиваете что-то, что ранее имело другое значение.