gpt4 book ai didi

c++ - 需要有关对象/连接池项目的 RAII 设计的建议

转载 作者:搜寻专家 更新时间:2023-10-31 01:53:04 24 4
gpt4 key购买 nike

首先我会说我已经研究了几天,试图弄清楚什么是“正确的方法”。在对 RAII/池设计/智能指针进行了大量谷歌搜索之后,并没有得出明确的结论(除了可能没有绝对的“正确方法”),我想也许是时候让更有知识的人为我指明正确的方向了.

我正在构建一个对象池,并且我正在努力确保客户端代码可以根据需要使用 RAII。

涉及 3 个实体:

  • 资源。构建成本高,重用成本低(在发布时检查其状态并非易事)。难以复制,因为它用自己分配的内存/资源包装了一些 C 结构。
  • 包装器/句柄。资源的包装器。在 ctor 上获得资源,在 dtor 上释放它。
  • Controller /池。维护资源池并管理客户对它们的使用,通过 Wrapper 或由客户自行决定直接使用。

我在下面展示了我提出的一个简化示例。在函数 DoSomethingElse() 中,您可以看到我在做什么 - 我获得了对 Wrapper 的引用,并且在作用域的末尾调用了它的 dtor,并释放了 Resource到游泳池。

我的问题与 Factory::GetResource() 的定义有关。这里介绍的简化版本只是每次分配一个新的;我的实际实现检查池中是否有可用资源(如果没有可用资源则创建一个),将其标记为正在使用,并返回对它的引用。

我宁愿避免必须为资源定义适当的复制构造函数,因此按引用而不是按值返回。 Resource 保证比调用者活得更久,并且 Controller 在应用程序的整个生命周期中保持所有权——它们不会交给客户端代码进行生命周期管理。当然,如果客户要求直接引用,即没有 Wrapper,那么一切都将失败。

这个设计合理吗?使用 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;
}

最佳答案

RAII 实际上是关于所有权的。谁拥有该对象,他们放弃所有权后需要做什么?

您所描述的情况是资源确实由 Controller 拥有。资源对象的生命周期由 Controller 管理。

资源的用户实际上只是“锁定”资源,将其标记为“正在使用”,但他们并不取得资源的所有权。它们不会影响其使用生命周期。 (你可以说他们拥有一把锁,然后就是他们需要管理的资源)

所以我建议公开类似 std::unique_ptr<Resource> 的内容,这是使用自定义删除器创建的。 (并且可以通过 controller.getResource() 调用的值返回

用户可以用这个来做unique_ptr他们喜欢什么:它不可复制,但可以移动,一旦超出范围,它就会调用其自定义删除器,在 Controller 中将其标记为“未使用”,有效地将其返回到池中

这样你就可以按值返回一个对象,这对客户端来说很好用也很简单,而且你可以完全避免暴露“未包装”的资源对象:客户端总是将它们包装在 unique_ptr 中。 ,这消除了很多潜在的错误。

关于c++ - 需要有关对象/连接池项目的 RAII 设计的建议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11638032/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com