#c #inheritance #move-semantics #assignment-operator
#c #наследование #переместить-семантика #оператор присваивания
Вопрос:
Этот код компилируется и выполняется нормально:
#include <iostream>
class Base
{
public:
Base(int value)
: clean_(true)
{
value_ = new int;
*value_ = value;
}
~Base()
{
if(clean_)
delete value_;
}
Base(Baseamp;amp; other) noexcept
: value_{std::move(other.value_)},
clean_(true)
{
other.clean_=false;
}
Baseamp; operator=(Baseamp;amp; other) noexcept
{
value_ = std::move(other.value_);
other.clean_=false;
clean_=true;
}
void print()
{
std::cout << value_ << " : " << *value_ << std::endl;
}
int* value_;
bool clean_;
};
class A : public Base
{
public:
A(int v1, double v2) : Base(v1)
{
a_ = new double;
*a_ = v2;
}
A(Aamp;amp; other) noexcept
: Base(std::forward<Base>(other)),
a_(std::move(other.a_))
{}
Aamp; operator=(Aamp;amp; other) noexcept
{
// should not the move assignment operator
// of Base be called instead ?
// If so: how ?
this->value_ = std::move(other.value_);
other.clean_=false;
this->clean_=true;
a_ = std::move(other.a_);
}
void print()
{
std::cout << this->value_ << " "
<< *(this->value_) << " "
<< a_ << " " << *a_ << std::endl;
}
double* a_;
bool clean_;
};
A create_a(int v1,double v2)
{
A a(v1,v2);
return a;
}
int main()
{
Base b1(20);
b1.print();
Base b2 = std::move(b1);
b2.print();
A a1(10,50.2);
a1.print();
A a2 = std::move(a1);
a2.print();
A a3 = create_a(1,2);
a3.print();
}
A является подклассом Base.
Код оператора присваивания перемещения A повторяет код оператора присваивания Base.
Есть ли способ избежать этой репликации кода?
Комментарии:
1. Использовать
unique_ptr<int>
и вообще не писать эти методы?2. Собираетесь ли вы иметь две копии
clean_
объектов типаA
in?3. В качестве примечания: вы знаете, что
std::move
не выполняет перемещение, но что это просто приведение? Так чтоa_ = std::move(other.a_);
не имеет особого смысла, посколькуa_
это просто указатель.4. @t.niese чтобы убедиться, что я понял, вы имеете в виду, что a_=std::move(other.a_) эквивалентно a_ = other.a_ ?
5. Для показанного кода результат эквивалентен.
std::move
это просто приведение кr-value
, и значениеother.a_
будет скопировано в обоих случаях в данном случае. Таким образом, вы можете просто написатьa_ = other.a_
в этом случае.
Ответ №1:
Измените int* value_;
на int value_;
и double* a_;
на double a_;
, и вам больше не нужно писать какие-либо специальные функции-члены, поскольку предоставленные компилятором значения по умолчанию просто работают ™
Если вам действительно нужно динамическое выделение памяти, то используйте тип RAII, такой std::vector
как std::unique_ptr
, std::shared_ptr
,,, и т.д. на свое место, поскольку они предназначены для правильного копирования и / или перемещения.
Комментарии:
1. Для этого конкретного примера это имеет смысл, но это всего лишь минимальный код для прояснения вопроса. Как вы вызываете оператор назначения перемещения базового класса, учитывая, что этот последний не такой тривиальный, как приведенный здесь?
2. @Vince Хитрость заключается в использовании типов RAII. Тогда вам не нужно ничего делать, вам будет предоставлено правильное поведение. Если вы действительно хотите вызвать назначение перемещения базового класса, тогда сделайте
Base::operator=(std::move(other));
, и это вызовет оператор присваивания перемещения базы.3. спасибо за ответ, это сработало! (Мой исходный код манипулирует указателями на некоторую разделяемую память между процессами.)