2016-09-06 23 views
3

変更できないサードパーティコードを使用しているときに問題が見つかりました。私はオブジェクトメンバーのコピーを作る必要があります。内部メンバーの1人が私的代入演算子を持っているため、これを厳密に行うことはできません。私が見つけた唯一の解決策は難しいので、私のプログラムに影響を与える可能性のある赤色のライトがあるかどうか尋ねたいと思います。代入演算子の代わりに配置演算子とコピーコンストラクタを使用

ここで私は(が、私はそれを変更できないことを覚えておいてください!)を扱っています単純化されたコードです:

#include <iostream> 
#include <algorithm> 

class MBool 
{ 
public: 
    MBool() {}; 
    MBool(const MBool& arg) {} 
private:  
    MBool& operator=(const MBool& arg); 
}; 

class InnerContent { 
private: 
    int* pBuffer; 

public: 
    InnerContent() { 
     pBuffer = new int[20]; 
     std::cout << "InnerContent()" << std::endl; 
    } 

    InnerContent(const InnerContent& otherInnerContent) { 
     pBuffer = new int[20]; 
     std::copy(otherInnerContent.pBuffer, otherInnerContent.pBuffer + 20, pBuffer); 
     std::cout << "InnerContent(const InnerContent&)" << std::endl; 
    } 

    ~InnerContent() { 
     std::cout << "~InnerContent()" << std::endl; 
     delete [] pBuffer; 
     pBuffer = nullptr; 
    } 

    virtual void someVirtualFunction() {} 
}; 

class Content { 
public: 
    InnerContent innerContent; 
    int someNumber; 
    MBool boolVar; 

    Content() { 
     std::cout << "Content()" << std::endl; 
    } 
    ~Content() { 
     std::cout << "~Content()" << std::endl; 
    } 
    Content(const Content& otherContent) : 
     innerContent(otherContent.innerContent), 
     someNumber(otherContent.someNumber), 
     boolVar(otherContent.boolVar) 
    { 
     std::cout << "Content(const Content&)" << std::endl; 
    } 

    virtual void someVirtualFunction() {} 
}; 

class A { 
public: 
    Content content; 

    A() { std::cout << "A()" << std::endl; } 
    ~A() { std::cout << "~A()" << std::endl; } 
}; 

class B { 
public: 
    Content content; 

    B() { std::cout << "B()" << std::endl; } 
    ~B() { std::cout << "~B()" << std::endl; } 
}; 

そして、ここでは、私は(これだけのコードを変更することができますそれを行うことを約だものです私の解決策は、Contentデストラクタを手動で呼び出して、Contentとその内部クラス内の動的に割り当てられたメモリを解放することです。スタック上のメモリは変更されていないので、存在するコピーコンストラクタを呼び出し、必要なものを正確に実行するplacement-new演算子で再利用できます。主な機能スコープが終わると、オブジェクトは適切にクリーンアップされます。

コード出力:

InnerContent() 
Content() 
A() 
InnerContent() 
Content() 
B() 
--- Before copying 
~Content() 
~InnerContent() 
InnerContent(const InnerContent&) 
Content(const Content&) 
--- After copying 
~B() 
~Content() 
~InnerContent() 
~A() 
~Content() 
~InnerContent() 

私は、このクラスは、新しいバージョンに更新することができますので、コピーしたすべてのフィールド私自身の機能をしたくないと私はコピーしないであろう追加のフィールドがあるかもしれないし、おそらく誰もそれを修正することを覚えていないでしょう。

質問:これはメモリリークやメモリ破損の原因になると思いますか?あなたは私が言及しなかった何かの問題を見ますか?

+2

代わりに、 'Content'へのスマートポインタを使用してください。指先を新しいものに簡単に置き換えることができます。 –

+2

コピーコンストラクタが最新の状態になっていることを確認してください。問題が発生します。.......私は実際にこれに似た戦略を実際に使っています。 – DarthRubik

+1

'copyContent(x、x)'を実行しますか? – Barry

答えて

2

基本的には、アイデアは機能するはずです。デストラクタを呼び出すことを忘れることから身を守るために、私はクラステンプレートのようなスマートなポインタの中に考えるべきだと思います。この例では、実際にはポインタをラップしませんが、コンテンツオブジェクト自体はラップします。

template <typename ContentType> 
class content_wrapper { 
    private: 
     ContentType content_; 
    public: 
     content_wrapper() : content_ {} {}; 
     content_wrapper(const content_wrapper& other) : 
      content_{other.content_} {}; 

     content_wrapper& operator = (const content_wrapper& other) { 
      content_.~ContentType(); 
      new (&content_) ContentType(other); 
      return *this; 
     } 

     ContentWrapper& operator *() { 
      return content_; 
     } 
     ContentWrapper* operator ->() { 
      return &content_; 
     } 
}; 

今、あなたはそのようにそれを使用することができます:

class A { 
    public: 
     content_wrapper<Content> content; 

     A() { std::cout << "A()" << std::endl; } 
     ~A() { std::cout << "~A()" << std::endl; } 
}; 

class B { 
    public: 
     content_wrapper<Content> content; 

     B() { std::cout << "B()" << std::endl; } 
     ~B() { std::cout << "~B()" << std::endl; } 
}; 

int main() { 
    A a; 
    B b; 

    b.content = a.content; // the wrapper will take care. 

    b.content->someVirtualFunction(); 
} 

簡単に読み取るために、あなたがコンテンツオブジェクトを割り当てるたびに、デストラクタの呼び出しを忘れることはできません。

+0

お返事ありがとうございます。クラスAとBもライブラリにありますので、メンバーにラッパーを適用することはできませんが、私はそのアイデアが気に入っています。 –

+1

@SzymonKordyacznyそして、 'Content'の代わりに' A'と 'B'をラップしようとするかもしれません。 BTW私はちょうどバグを見てすぐに私の答えを編集します。 – cdonat

関連する問題