对象管理器的最佳实践

时间:2010-02-25 21:11:46

标签: c++ multiplayer

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

为了避免内存碎片,我计划分配一个允许客户端最大数量的对象池。为此,我正在编写一个像这样的客户端对象管理器:

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

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

实施将类似于:

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 ++的新手,所以如果我说错了,请纠正我)。

在主程序中,我正在思考如下:

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)抱歉我的英语不好:)

2 个答案:

答案 0 :(得分:3)

几点意见:

  • 使用std :: vector来保存客户端对象,而不是某种本地结构。它会让你的生活更轻松
  • 我认为如果get()返回一个引用就好了,前提是用户确实知道如果引用挂起太长时间引用就会失效
  • 如果元素不存在,我会在get()中抛出异常;这就是异常的含义,它将允许您在适当的级别处理缺少的元素

对于(2),你可以处理适当的信号并调用dispose()。我想你可能想在退出之前关闭套接字。

答案 1 :(得分:1)

使许多成员静态不会使它成为“静态类”。它只是一个类似于任何其他类的类,具有静态成员函数。你无论如何都不需要这样做:只需将ClientManager作为普通类,并在游戏中创建一个类。

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

你不应该担心内存碎片 - 这是一个如此深奥的低级细节,你甚至不应该考虑它。它对你来说是一个问题的机会是天文数字很小。但即使它是一个问题,我们也无法根据您在此处发布的内容进行诊断,因为我们不知道什么构成了Client类。如果Client类本身引用其他地方的各种内存,那么在ClientManager类中有一个精心管理的池是没有意义的。在这个阶段,您应该专注于编写健壮且正确的代码,并在需要时进行优化。

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