2017-06-27 1 views
1

サイドプロジェクト用の独自のGUIライブラリをローリングしています。スマートポインタを使用するためのリファクタリングしかし、私は問題に直面した。オブジェクトのライフタイムを管理するライブラリー、スマートポインタまたは生データを使用しますか?

明白な理由から、スマートポインタをDLL境界をまたいで使用したくないことに気付いています。しかし、私はアプリケーションコードで 'new'を使って汚いと感じます。以下を参照してください:

私はC++ 98スタイルとセマンティクスを使い、自分で処理する方がよいです。明らかに、インターフェイスの境界(つまりAddControl)にスマートポインタを渡したくないのですが、コントロールのライフタイムを処理する必要はありません。

さらに、私はnew Button("testButton")を使用して実際に汚いと感じます。

+0

これらの「明白な理由」は何ですか?個別のヒープは、スマートポインタまたは生ポインタによって所有されているかどうかにかかわらず、動的に割り当てられたオブジェクトに影響します... – Quentin

+3

@Quentin彼はABI問題について話していると思います。ダイナミックライブラリでは、C++のABIは定義されていないので、CのABIはよく定義されているので、Cのインタフェースを持つ方が簡単です。 – nefas

+0

@nefasが正しいです。 – keelerjr12

答えて

1

プライマリ実行可能ファイルとは異なるコンパイラ/バージョン/プラットフォームでコンパイルされたDLLをリリースしないことを保証すれば、ABIの問題は回避できます。あなたのインターフェイスデザインに関するいかなる速度で

void AddControl(Control& control) { 
    mControls.emplace_back(&control) 
} 

  • Controlが多型である(あるいは、少なくとも、あなたがどのようなコードに基づいているように見えるので、あなたは、ここで問題を持っています提供されています)。つまり、完全なオブジェクトを取得するために参照またはポインタで渡す必要がありますが、
  • 生ポインタを維持しなければならないインターフェイスを短時間でも公開したくない場合は、 gをアプリケーションに追加します。

これは私がこの問題を回避設計する方法を次のとおりです。

class Window { 
public: 
    void AddControl(std::unique_ptr<Control> control) {//Note we're passing by value! 
     mControls.emplace_back(std::move(control)); 
    } 
private: 
    std::vector<std::unique_ptr<Control>> mControls; 
}; 

次に、アプリケーション内:これは必ずしも愚かな何かをしてからユーザーを停止しないことを

class MyFinanceApp : public Application { 
public: 
    MyFinanceApp() : mMainWindow(make_unique<Window>()) { 
     mMainWindow->AddControl(std::make_unique<Button>("testButton")); 
    } 

private: 
    std::unique_ptr<Window> mMainWindow; 
}; 

注意、like

std::unique_ptr<Window> window_ptr = std::make_Unique<Window>(); 
Button * button = new Button("This won't be properly deleted!"); 
window_ptr->AddControl(std::unique_ptr<Button>{button}); 
delete button; //Whoops! 

...しかし、それらを最初から止めているものは何でもあります。

代替案は、コントロールに関連付けられた「工場」を持つことです。

Control & AddControl(std::unique_ptr<Control> control) { 
    mControls.emplace_back(std::move(control)); 
    return *mControls.back(); 
} 

struct ControlFactory { 
    static Button & create_button(Window & window, std::string button_text) { 
     std::unique_ptr<Button> button_ptr = std::make_unique<Button>(button_text); 
     Button & ref = *button_ptr; 
     window.AddControl(std::move(button_ptr)); 
     //ref will NOT be invalidated, because the object will still exist in memory, 
     //in the same location in memory as before. Only the unique_ptr will have changed. 
     return ref; 
    } 
}; 

をそして、あなたは、単にエンドユーザーのプログラマーによってそのコンストラクタへの直接アクセスを許可していないすべてのControlサブクラスのアクセス修飾子を変更する必要があるだろう:私たちは、最初のAddControlに変更を行う必要があると思います。このような何かはおそらく十分であろう:

class Button : public Control { 
    /*...*/ 
protected: 
    Button() {/*...*/} 
    Button(std::string text) {/*...*/} 
    friend class ControlFactory; //Allows ControlFactory to access, even though access is protected. 
}; 

を次にユーザーが、それはあなたがこれらの参照は、アプリケーション自体よりも長生きしないことを保証する必要があるわけんが、ポインタよりも安全である彼らの最後の参照が格納されます。

関連する問題