copy/move ctors/assignment operator と dtor (Rule of Five) の実装を使用して、抽象基本クラスに関連するエラーC2248を解決しようとすると、いくつかの質問が出てきます。
1) unique_ptr データ メンバーが自動的に処理されるときに、主に dtor に関連する 5 のルールが適用されるのはなぜですか? 所有者が範囲外になると unique_ptrs が自動的に破棄されるため、dtor の実装は空のままにしておく必要がありますか?
2) 別のクラスが、同じ型のベクトルの型 std::unique_ptr のメンバーを持っているとします。このクラスをコピー可能にするためには、unique_ptr データ メンバーを複製するコピー ctor とコピー代入演算子が必要ですか? 私はこの解決策を見てきましたが、所有権管理をほとんど考慮せずにエラーを単独で削除するために、元のポスターが shared_ptr に切り替えたようです。これは正しい戦略ですか?
3) unique_ptr のベクトルに関連する上記の質問 2 と同じケースを検討してください。ベクトルを clear() する呼び出しを dtor に含める必要がありますか?
4) Derived1 の代入演算子が正しくありません。ただし、基本クラスにはコピー/移動 ctors (4/5 の規則) があるため、コピーおよび移動代入演算子があるはずです。これらは抽象的であり、インスタンスが割り当てられないため、クラスの外で実際に使用することはできません。しかし、派生クラスからこのコードを利用するにはどうすればよいでしょうか? 各派生クラスは、基本データ メンバーと独自のデータ メンバーを移動/コピーできる必要があります。どうすればいいのかわからない。
#include <algorithm>
#include <memory>
#include <vector>
#include <iostream>
class Base{
public:
Base() : m_subBases(){};
/* copy ctor */
Base(const Base& other) : m_subBases(){
*this = other;
};
/* move ctor */
Base(Base&& other) : m_subBases(){
*this =std::move( other);
};
/* Move assignment operator*/
Base& operator=(Base&& other){
m_subBases = std::move(other.m_subBases);
return *this;
};
/* Copy assignment operator */
Base& operator=(const Base& other){
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
return *this;
};
/* virtual dtor */
virtual ~Base(){
m_subBases.clear();
};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const= 0;
/* Do something */
virtual void execute(float f) = 0;
//Omitted data member access methods
protected:
std::vector < std::unique_ptr <Base> > m_subBases;
};
class Derived1 : public Base{
public:
Derived1() : Base(){};
/* copy ctor */
Derived1(const Derived1& other) : Base(other){
*this = other;
};
/* move ctor */
Derived1(Derived1&& other) : Base(std::move(other)){
*this = std::move(other);
};
/* Move assignment operator*/
Derived1& operator=(Derived1&& other){
//This is redundant when called in the move ctor because
// of the call to Base(std::move(other))
m_subBases = std::move(other.m_subBases);
m_string = other.m_string;
return *this;
};
/* Copy assignment operator */
Derived1& operator=( const Derived1& other){
//This is redundant when called in the copy ctor because
// of the call to Base(other)
for(int i = 0; i < other.m_subBases.size(); i++)
m_subBases.push_back(other.m_subBases[i]->clone());
m_string = other.m_string;
return *this;
};
/* virtual dtor */
virtual ~Derived1(){};
/* Used for creating clones of unique_ptrs */
virtual std::unique_ptr <Base> clone() const{
return std::unique_ptr <Base> (new Derived1(*this));
};
virtual void execute(float f){
std::cout << "Derived1 " << f << std::endl;
};
protected:
std::string m_string;
};