简体   繁体   English

C ++设计:池和指针VS客户端 - 服务器

[英]C++ Design: Pool and pointers VS client-server

I'm designing a software tool in which there's an in-memory model, and the API user can get objects of the model, query them and set values. 我正在设计一个软件工具,其中有一个内存模型,API用户可以获取模型的对象,查询它们并设置值。

Since all the model's objects belong to a single model, and most operations must be recorded and tested, etc., each created object must be registered to the Model object. 由于所有模型的对象都属于单个模型,并且大多数操作必须进行记录和测试等,因此必须将每个创建的对象注册到Model对象。 The Model stores all objects as std::unique_ptr since it's the only owner of them. Model将所有对象存储为std::unique_ptr因为它是它们的唯一所有者。 When needed, it passes raw pointers to users. 需要时,它会将原始指针传递给用户。

What makes me worry is the possibility that the user calls delete on these pointers. 让我担心的是用户在这些指针上调用delete的可能性。 But if I use std::shared_ptr , the user can still use get() and call delete on that. 但是如果我使用std::shared_ptr ,用户仍然可以使用get()并在其上调用delete So it's not much safer. 所以它不是更安全。

Another option I though of is to refer to objects by a name string, or pass ObjectReference objects instead of the real objects, and then these ObjectReferences can be destroyed without affecting the actual stored object. 我的另一个选择是通过名称字符串引用对象,或者传递ObjectReference对象而不是真实对象,然后可以销毁这些ObjectReferences而不影响实际存储的对象。

These References work somewhat like a client: You tell them what to do, and they forward the request to the actual object. 这些引用有点像客户端:您告诉他们该做什么,并将请求转发给实际对象。 It's a lot of extra work for the developer, but it protectes the pointers. 这对开发人员来说是一项额外的工作,但它会保护指针。

Should I be worried about the pointers? 我应该担心指针吗? Until now I was using smart pointers all the time, but now I need to somehow allow the user to access objects managed by a central model, without allowing the user to delete them. 到目前为止,我一直在使用智能指针,但现在我需要以某种方式允许用户访问由中央模型管理的对象,而不允许用户删除它们。

[Hmmm... maybe make the destructor private, and let only the unique_ptr have access to it through a Deleter?] [嗯...也许让析构函数变得私有,只允许unique_ptr通过Deleter访问它?]

You shouldn't bother about users calling delete on your objects. 您不应该为在对象上调用delete用户而烦恼。 It's one of those things that are perfectly fine as a documented constraint, any programmer violating that only deserves whatever problem he runs into. 这是一个完全没有作为记录约束的事情之一,任何违反这个的程序员只应该遇到他遇到的任何问题。

If you still really want to explicitly forbid this, you could either write a lightweight facade object that your users will pass by value (but it can be lot of work depending on the number of classes you have to wrap) or, as you said, make their destructor private and have unique_ptr use a friend deleter. 如果您仍然真的想要明确禁止这个,那么您可以编写一个轻量级的Facade对象,您的用户将按值传递(但是根据您必须包装的类的数量,这可能很多工作),或者如您所说,使他们的析构函数私有,并让unique_ptr使用friend删除。

I for one am not fond of working through identifiers only, this can quickly lead to performance issues because of the lookup times (even if you're using a map underneath). 我一个人不喜欢只使用标识符,由于查找时间(即使你在下面使用地图),这很快就会导致性能问题。


Edit: Now that I think of it, there is a way in between identifiers and raw pointers/references: opaque references . 编辑:现在我想到了,标识符和原始指针/引用之间有一种方法: 不透明引用

From the point of view of the users, it acts like an identifier, all they can do is copy/move/assign it or pass it to your model. 从用户的角度来看,它就像一个标识符,他们只能复制/移动/分配它或将其传递给你的模型。

Internally, it's just a class with a private pointer to your objects. 在内部,它只是一个带有指向对象的私有指针的类。 Your model being a friend of this class, it can create new instances of the opaque reference from a raw pointer (which a user can't do), and use the raw pointer to access the object without any performance loss. 您的模型是此类的朋友,它可以从原始指针(用户无法做到)创建不透明引用的新实例,并使用原始指针访问该对象而不会造成任何性能损失。

Something along the lines of: 有点像:

class OpaqueRef
{
    // default copy/move/assignment/destructor
private:
    friend class Model;
    Object* m_obj;
    OpaqueRef(Object& obj) : m_obj(&obj) {}
};

Still, not sure if it's worth the trouble (I stand by my first paragraph), but at least you got one more option. 不过,不确定它是否值得麻烦(我支持我的第一段),但至少你还有一个选择。

Personally, I'd keep the internal pointer in the model without exposing it and provide an interface via model ids, so all operations go through the interface. 就个人而言,我将内部指针保留在模型中而不暴露它,并通过模型ID提供接口,因此所有操作都通过接口。

So, you could create a separate interface class that allows modification of model attributes via id. 因此,您可以创建一个单独的接口类,允许通过id修改模型属性。 External objects would only request and store the id of the object they want to change. 外部对象只会请求并存储他们想要更改的对象的id。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM