首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对象管理器的最佳实践

对象管理器的最佳实践
EN

Stack Overflow用户
提问于 2010-02-26 05:11:46
回答 2查看 2.5K关注 0票数 2

我对c++编程比较陌生,我正在为一个多人游戏编写一个对象管理器,但是我对如何管理客户端对象有一些疑问。客户端对象由连接的客户端参数(如IP、连接时间、接收数据等)组成。

为了避免内存碎片,我计划分配一个具有最大客户端数量的对象池。为此,我编写了一个客户端对象管理器,如下所示:

代码语言:javascript
运行
复制
ClientManager.h

#include "Client.h"

class ClientManager { 
public: 
static void init(int max); //initialize pool (allocate memory) 
static void dispose(); //dispose pool (deallocate memory) 
static bool add(int socketFd); //add connected client by its socket file descriptor 
static bool remove(int socketFd); //remove connected client by its socket fd
static Client& get(int socketFd); //get the client object by its socket fd

private: 
Client* clientList; //array of allocated clients objects
int maxClient; //max number of connected clients allowed

请注意,该类将仅以静态方式调用,因此没有构造函数/析构函数。这个类必须是静态的,因为客户端数据必须可以在不同类型的对象之间读取/修改。

其实现将类似于:

代码语言:javascript
运行
复制
ClientManager.cpp

void ClientManager::init(int max) {
maxClient = max;
clientList = new Client[maxClient];
}

void ClientManager::dispose() {
maxClient = 0;
delete [] clientList;
clientList = NULL;
}

bool ClientManager::add(int socketFd) {
//search pool for non-initialized object
//if(there is a non-initializes object) { initialize it with socketFd and return true}
//else return false;
}

bool ClientManager::remove(int socketFd) {
//search pool for socketFd
//if(socketFd found) { clear object (make it non-initialized) and return true}
//else return false
}

Client& ClientManager::get(int socketFd) {
//search for object position
if(pos) return clientList[pos];
else ???????
}

现在,我如何管理get函数中的对象返回呢?通过引用它是最好的选择吗?我不想返回指针,但如果这是我最后的选择,我可以接受它。我想我可以确保我只在池中注册(初始化)对象,如果是这样,是否有必要在get函数中进行此检查?我不想要断言,因为我希望代码是健壮的,并且在运行时不会停止(我是C++的新手,所以如果我说错了什么,请纠正我)。

在主程序中,我是这样思考的:

代码语言:javascript
运行
复制
Daemon.cpp

#include "ClientManager.h"

int main(...) {
ClientManager::init(100);

while(1) {
//do server stuff
//get onConnect event (new client is connecting)
//get onDisconnect event (connected client has gone offline)
//get onDataReceived event (connected client has sent data)
}
}

void onConnect(int socketFd) {
ClientManager::add(socketFd);
}

void onDisconnect(int socketFd) {
ClientManager::remove(socketFd);
}

void onDataReceived(int socketFd) {
do_something(ClientManager::get(socketFd).data);
}

我做得对吗?谢谢

备注:

1)这段代码一直在我的脑海中,我在这里输入了它,所以我可能忘记了什么。

2)程序只有在被终止时才会终止(我使用的是linux),所以在主程序中不会显式调用ClientManager dispose方法(因为它是一个静态类)。再次声明,如果我说错了什么,请告诉我!

3)对不起,我的英语不好:)

EN

回答 2

Stack Overflow用户

发布于 2010-02-26 05:25:37

下面是几条评论:

  • 使用std::vector来保存客户端对象,而不是某种自行开发的结构。它会让你的生活变得更轻松,如果
  • ()返回一个引用也没问题,前提是用户知道如果他们持有引用太长时间,引用可能会失效
  • 如果元素不存在,我会在get()中抛出一个异常;这就是异常的用处,它将允许你在适当的级别上处理缺失的元素

至于(2),您可以处理适当的信号并调用dispose()。我想您可能想在退出之前关闭插座。

票数 3
EN

Stack Overflow用户

发布于 2010-02-26 18:36:14

将大量成员设置为静态并不会使其成为“静态类”。它只是一个类,和其他类一样,都有静态成员函数。无论如何,您都不需要这样做:只需使ClientManager成为一个普通的类,并在游戏中创建其中的一个。

我再次建议使用std::vector而不是您自己的数组。这将使您的代码更健壮,并使您更容易设置客户端,为每个客户端使用适当的构造函数,而不是为许多客户端使用某种类型的默认构造函数。

你不应该担心内存碎片-这是一个如此深奥的底层细节,你甚至不应该考虑它。对你来说,这是一个极小的问题。但是即使它是一个问题,我们也不能根据您在这里发布的内容来诊断它,因为我们不知道Client类的组成。如果客户端类本身在其他地方引用了所有类型的内存,那么在ClientManager类中使用一个精心管理的池就没有意义了。在这个阶段,您应该专注于编写健壮和正确的代码,并在以后需要时进行优化。

您也可以从ClientManager::get返回一个指针。只需确保在使用它之前检查它是否为null。如果您选择不同的接口,则可以完全消除从ClientManager返回客户端的需要。将操作do_something与数据一起传递到ClientManager的一个成员中,该成员将查找客户端并在找到客户端时调用该操作,如果未找到则报告错误。(尽管如果您的ClientManager是正确的,那么没有理由找不到它。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2337650

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档