9

unique_ptr と move-semantics の両方を利用する pimpl の例はまだ見たことがありません。

CHelper クラスを STL 派生コンテナーに追加し、pimpl を使用して CHelper の機能を隠したいと考えています。

これは正しく見えますか?

Derived.h

class CDerived : public set<CSomeSharedPtr>, public CHelper  
{
//...
};

`

Helper.h

// derived containers need to support both copy and move, so CHelper does too  

class CHelper  
{  
private:  
    class impl;  
    unique_ptr<impl> pimpl;  

public:  
//--- default: need both cotr & cotr (complete class) in order to use unique_ptr<impl>  
    CHelper();  
    ~CHelper();  

//--- copy  
    CHelper(const CHelper &src);         //copy constructor  
    CHelper& operator=(const CHelper &src);//assignment operator  

//--- move  
    CHelper(CHelper &&src);         //move constructor  
    CHelper& operator=(CHelper &&src);//move operator  

//--- expose public methods here  
    void SetModified(BOOL bSet=TRUE);  
};  

Helper.cpp

//===========================  
class CHelper::impl  
{  
public:  
BOOL m_bModified; //has the container been modified (needs to be saved)  
// ... other data  

impl() {m_bModified = FALSE;}  

//--- copy cotr/assign  
impl(const impl &src)  
{  
  *this = src;  
}  

void operator=(const impl &src)   
{  
  m_bModified = src.m_bModified;  
  // ...other data  
}  

//--- move cotr/assign ?? do I need to write move cotr/assign ??   

};  

//============================  
CHelper::CHelper() : pimpl(unique_ptr<impl>(new impl())) {}

CHelper::~CHelper() {}  

//--- copy  
CHelper::CHelper(const CHelper &src)  
: pimpl(unique_ptr<impl>(new impl(*src.pimpl))) {}

CHelper& CHelper::operator=(const CHelper &src)  
{  
  if (this != &src)  
    *pimpl = *src.pimpl;  

  return *this;  
}  

//--- move  
CHelper::CHelper(CHelper &&src)  
{  
  if (this != &src)  
  {  
    pimpl = move(src.pimpl); //use move for unique_ptr  
    src.pimpl.reset(nullptr);//leave pimpl in defined / destructable state  
  }  
}  

CHelper& CHelper::operator=(CHelper &&src)  
{  
    if (this != &src)  
    {  
      pimpl = move(src.pimpl); //use 'move' for unique_ptr  
      src.pimpl.reset(nullptr);//leave pimpl in defined / destructable state  
    }  
    return *this;  
}  
4

1 に答える 1

4

の唯一のメンバーCHelperは aunique_ptrであり、copy のデフォルトの実装はベースとメンバーのコピーを呼び出していることを考慮すると、move のデフォルトの実装はベースとメンバーのmoveを呼び出しているためCHelper、 ctorをオーバーライドする必要はありません。と割り当てます。デフォルトに仕事をさせてください。適切な unique_ptr 移動コンストラクターと演算子を呼び出すだけです。

CHelperCDerived を作成するための組み合わせについてset<...>...これは「正規の設計」setではありません (OOP クラスではありません...そして CHelper もそうではありません)が、適切に使用すれば機能します (を割り当てようとしないでください)。CDerivedそのCHelper*上で広告呼び出しを削除しないと、涙を流してしまいます)。それらが何を目的としているのかを理解するのに十分な情報がありません。

問題が「CHelperもコピーできるようにしたい」という場合は、おそらくこのようなイディオムに従う方がよいでしょう(#includeそしてusing namespace離れて...)

class CHelper
{
    struct impl
    {
       .....
    };
public:
    // create and initialize
    CHelper() :pimpl(new impl) {}

    // move: just keep the default
    CHelper(CHelper&& a) = default;

    // copy: initialize with a copy of impl
    CHelper(const CHelper& a) :pimpl(new impl(*a.pimpl)) {}

    CHelper& operator=(CHelper a) //note: pass by value and let compiler do the magics
    { 
        pimpl = move(a.pimpl); //a now nullifyed, but that's ok, it's just a value
        return *this; 
    }

    ~CHelper() = default; //not really necessary
private:
    unique_ptr<impl> pimpl;
};

もちろん、必要に応じて宣言と実装を自由に分離してください。

John Balcom のコメントに従って編集します。

はい、もちろんコードは変更されますが、その内容は変わりません。(unique_ptr が意味を持つように)宣言struct impl;を転送してから、別の場所で struct を宣言することができます (CHelper のすべての実装が行われる CPP ファイルにある可能性があります)。CHelperCHelper::impl

ここで唯一の注意点は、CPP ファイル内で一貫した unique_ptr インスタンス化 (impl デストラクタを呼び出さなければならない) を持つために、CPP ファイルで CHelper::impl にコンストラクタとデストラクタの両方を定義する必要があることです。そうしないと、一部のコンパイラでは、CHelper 宣言を含むすべてのファイルで「不完全な型の使用」エラーが発生するリスクがあります。

2 番目のポイント (から派生std::set) については、これは C++ プログラミングの物議を醸す側面です。C++ 自体には関係ありませんが、オブジェクト指向プログラミングスクールでは、「継承」「ある」を意味し、「ある」「オブジェクト置換が可能」を意味します。そのため、ベースポインターが仮想でない場合、ベースポインターを介してオブジェクトを削除することはUBであるため、オブジェクトの代用をUBにするため、OOPスクールはドグマとして、仮想dtorを持たないクラスの継承を拒否します。彼らはプログラミングを始めたときに教育を受けていました。

私にとって、それはあなたの設計の問題ではありませんが、C++ の継承は "" ではなく、"は " のようなものであり、オブジェクトの置換を意味しないことを理解している彼らの欠点です (私にとっては、すべての C++ クラスがツールを使用して何か便利なことを行うのではなく、OOP オブジェクトです。私の立場をより明確にしたい場合は、ここまたはここを参照してください。仮想または互いに独立していない)。そうは言っても、あなたはそれらの人々と一緒に働かなければならないかもしれないので...彼ら自身の好きな宗教の実践で彼らに従わないことの長所と短所を評価してください.

于 2012-06-26T17:03:56.487 に答える