私はこれを数日間調査していて、それを行う「正しい方法」とは何かを理解しようとしていると言って始めます。RAII /プールデザイン/スマートポインターを何度も調べて、明確な結論に至らなかった後(絶対的な「正しい方法」がない場合を除いて)、もっと知識のある人が私を正しい方向に向ける時が来たのではないかと思いました。 。
オブジェクトプールを構築していて、必要に応じて、クライアントコードがRAIIを使用できることを確認しようとしています。
関係するエンティティは3つあります。
- リソース。構築に費用がかかり、再利用するのに半安価です(リリース時に状態を確認するのは簡単ではありません)。一部のC構造を独自に割り当てられたメモリ/リソースでラップするため、コピーが困難です。
- ラッパー/ハンドル。リソースのラッパー。ctorでリソースが与えられ、dtorでリリースされます。
- コントローラー/プール。リソースのプールを維持し、Wrapperを介して、またはクライアントの裁量で直接、クライアントによるそれらの使用を管理します。
私が思いついたものの簡単な例を以下に示します。関数DoSomethingElse()
では、私が何を求めているかを確認できます。ラッパーへの参照を取得し、スコープの最後でそのdtorが呼び出され、リソースがプールに解放されます。
私の質問はの定義と関係がありFactory::GetResource()
ます。ここに示す簡略化されたバージョンは、毎回新しいバージョンを割り当てるだけです。私の実際の実装では、プールで使用可能なリソースをチェックし(使用可能なリソースがない場合は作成します)、使用中としてマークを付け、そのリソースへの参照を返します。
リソースの適切なコピーコンストラクターを定義する必要はなく、値ではなく参照によって返されます。リソースは呼び出し元よりも長持ちすることが保証されており、コントローラーはアプリの存続期間を通じて所有権を維持します。ライフサイクル管理のためにクライアントコードに渡されることはありません。もちろん、クライアントが直接参照を要求した場合、つまりラッパーがない場合、すべての賭けは無効になります。
このデザインは音ですか?shared_ptrを使用したほうがよいでしょうか?または他のメカニズム/デザイン?
御時間ありがとうございます。
#include <iostream>
#include <vector>
using namespace std;
static int seq = 0; // POOR MAN'S SEQUENCE FOR INSTANCE IDs
class Resource
{
public:
Resource() : id(seq++) { cout << "Resource ctor: " << id << endl; }
~Resource() { cout << "Resource dtor: " << id << endl; }
private:
int id;
};
class Wrapper
{
public:
// ON ACTUAL IMPLEMENTATION, NOTIFY THE CONTROLLER OF THE RELEASE
~Wrapper()
{ cout << "Wrapper dtor: " << id << "Welease Bwian! Ee, I mean, the wesouwce" << endl; }
explicit Wrapper(Resource& r) : id(seq++), res(r)
{ cout << "Wrapper ctor: " << id << endl; }
int getID() const { return id; }
private:
int id;
Resource& res;
};
class Controller
{
public:
~Controller() { for (auto r : allres) delete r; }
Resource& GetResource();
private:
// SIMPLIFIED. I'M USING Boost PTR CONTAINER
vector<Resource *> allres;
};
// SIMPLIFIED. IT WOULD ACTUALLY GET A RESOURCE FROM THE POOL
Resource& Controller::GetResource()
{
Resource* newres = new Resource();
allres.push_back(newres);
return *(newres);
}
// SIMULATE GLOBAL CONTEXT
Controller& GetController()
{
static Controller f;
return f;
}
void DoSomething(Wrapper& wr)
{
cout << "DoSth INI" << endl;
cout << wr.getID() << endl;
cout << "DoSth END" << endl;
}
void DoSomethingElse()
{
cout << "DoSthElse INI" << endl;
Wrapper w(GetController().GetResource());
DoSomething(w);
cout << "DoSthElse END" << endl;
}
int main(int argc, char *argv[])
{
cout << "main INI" << endl;
cout << "Calling DoSthElse" << endl;
DoSomethingElse();
cout << "Called DoSthElse" << endl;
cout << "main END" << endl;
}