两个类之间的循环引用 [英] Circular references between two classes

查看:142
本文介绍了两个类之间的循环引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这必须是一个n00b问题,但我必须实现一个mockup客户端 - 服务器顺序交互应用程序,并且因为客户端 - 服务器调用的数量不同,我不能只是迭代外部函数中的步骤,总是获取数据从客户端,然后转发到服务器,反之亦然,所以我需要使我的服务器客户端类应该意识到彼此,以便他们可以在它们之间调用他们的公共方法。一种方法是设计为Singleton,但我希望以更简单的方式,更准确地说,使用循环引用:客户端存储对服务器的引用,服务器存储对客户端的引用。我知道这可能不是一个好的方法,它可能会导致调用堆爆炸



为了实现所描述的实现,我认为我可以使用 std :: shared_ptr ,因为 std :: unique_ptr 不会工作,如果我也想防止两个变量从main当我调用两个setters(右?)从被破坏。所以,这是我有(简化代码):

  #include< iostream& 
#include< memory>

类服务器;

class Client
{
public:
void SetServer(const Server& server);
private:
std :: shared_ptr< const Server>服务器;
};

void Client :: SetServer(const Server& server)
{
this-> server = std :: shared_ptr< const Server>(& server);
}

类服务器
{
public:
void SetClient(const Client& client);
private:
std :: shared_ptr< const Client>客户;
};

void Server :: SetClient(const Client& client)
{
this-> client = std :: shared_ptr< const Client>
}

int main()
{
服务器服务器;
客户端客户端;

server.SetClient(client);
client.SetServer(服务器);

//这里我要求客户端开始与服务器交互。
//当客户端
//耗尽所有需要发送到服务器进行处理的数据时,进程将终止

return 0;不幸的是,我的代码似乎试图调用客户端和服务器(隐式)破坏者多次或一些类似的讨厌的事情,我确信这是由我对如何 std :: shared_ptr 应该工作的理解不足造成的。请指导。

解决方案

您在堆栈上分配您的服务器和客户端实例,并且当 main()退出。你不想要 std :: shared_ptr 删除它们。因此,有两种解决方案:


  1. 在客户端和服务器中使用非托管指针,并在外部管理其生命周期。


  2. 在任何地方使用托管指针,包括 main()。请注意, shared_ptr 意味着所有权。在当前设计中,服务器拥有客户端,但是客户端拥有服务器。这是一个循环引用:默认情况下,它们永远不会被释放,除非你仍然可以重置其中一个指针。



    例如,客户端保持服务器活动,因此最后消失的客户端将降低服务器,如果没有其他shared_ptrs指向它。服务器会有一个 weak_ptr 给客户端,但客户端会有一个 shared_ptr 到服务器。






  
类服务器;

class Client
{
public:
void SetServer(const std :: shared_ptr< const Server>& server);
private:
std :: shared_ptr< const Server>服务器;
};

void Client :: SetServer(const std :: shared_ptr< const Server>& server)
{
this-> server = server;
}

class Server
{
public:
void SetClient(const std :: weak_ptr< const Client>& client);
private:
std :: weak_ptr< const Client>客户;
};

void Server :: SetClient(const std :: weak_ptr< const Client>& client)
{
this-> client = client;
}


int main()
{
std :: shared_ptr< Server>服务器(新服务器);
std :: shared_ptr< Client>客户端(新客户端);

server.SetClient(client);
client.SetServer(server);

// do stuff

return 0;
}


I know this must be a n00b question, but I have to implement a mockup client-server sequential interaction application, and because the number of client-server calls varies, I cannot just iterate the steps in an external function, always fetching data from the client and then forwarding it to the server and vice-versa, so I need to make my Server and Client classes be aware of each other so that they can call their public methods between themselves. One approach would be to design both as Singletons, but I was hoping to do it in a simpler way, more precisely using a circular reference: the client stores a reference to the server and the server stores a reference to the client. I am aware that this might not be a good approach, and it could cause the call stack to explode when it becomes too deep, so any improvements to my design are welcomed.

In order to achieve the described implementation, I thought that I could use std::shared_ptr, because std::unique_ptr won't work if I also want to prevent the two variables from main from getting clobbered when I call the two setters (right?). So, this is what I have (simplified code):

#include <iostream>
#include <memory>

class Server;

class Client
{
public:
    void SetServer (const Server &server);
private:
    std::shared_ptr<const Server> server;
};

void Client::SetServer (const Server &server)
{
    this->server = std::shared_ptr<const Server>(&server);
}

class Server
{
public:
    void SetClient (const Client &client);
private:
    std::shared_ptr<const Client> client;
};

void Server::SetClient (const Client &client)
{
    this->client = std::shared_ptr<const Client>(&client);
}

int main ()
{
    Server server;
    Client client;

    server.SetClient(client);
    client.SetServer(server);

    //Here I ask the client to start interacting with the server.
    //The process will terminate once the client
    //exhausts all the data it needs to send to the server for processing

    return 0;
}

Unfortunately, my code seems to try to call the Client and Server (implicit) destructors multiple times, or some similar nasty thing, and I'm certain that this is caused by my poor understanding of how std::shared_ptr is supposed to work. Please advise.

解决方案

You allocate your Server and Client instances on the stack, and they will be deleted when main() exits. You don't want std::shared_ptr deleting them as well. Thus, there are two solutions:

  1. Use unmanaged pointers within Client and Server, and manage their lifetimes externally.

  2. Use managed pointers everywhere, including main(). Do note that shared_ptr implies ownership. In the current design, a Server owns the client, but also a Client owns the server. That's a circular reference: by default, they'll never be freed, unless you reset one of those pointers while you still can.

    As an example, you can decide that the clients keep the server alive, thus last vanishing client will bring down the server if there are no other shared_ptrs pointing at it. The server would have a weak_ptr to the client(s), but the clients would have a shared_ptr to the server.

class Client;
class Server;

class Client
{
public:
    void SetServer (const std::shared_ptr<const Server> &server);
private:
    std::shared_ptr<const Server> server;
};

void Client::SetServer (const std::shared_ptr<const Server> &server)
{
    this->server = server;
}

class Server
{
public:
    void SetClient (const std::weak_ptr<const Client> &client);
private:
    std::weak_ptr<const Client> client;
};

void Server::SetClient (const std::weak_ptr<const Client> &client)
{
    this->client = client;
}


int main()
{
  std::shared_ptr<Server> server(new Server);
  std::shared_ptr<Client> client(new Client);

  server.SetClient(client);
  client.SetServer(server);

  // do stuff

  return 0;
}

这篇关于两个类之间的循环引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆