开发者

The right way to expose a complex short-lived object

开发者 https://www.devze.com 2023-02-02 16:06 出处:网络
I am developing a Darwinian evolution simulation. For performance reasons, it\'s written in C++. The sim is represented by an instance of World. The animals are represented by instances of Animal, a f

I am developing a Darwinian evolution simulation. For performance reasons, it's written in C++. The sim is represented by an instance of World. The animals are represented by instances of Animal, a fairly complicated object. World has two important methods:

animal_at(int i) 

and

evolve(int n). 

animal_at returns a non-null raw pointer to the instance of Animal that represents the i-th animal.

evolve advances the simulation possibly invalidating any pointer returned by animal_at. I want to make the sim and the animals easily accessible from outside. I have python-specific bindings, but i'm considering learning CORBA or Ice to implement a more generic interface. The problem is how I should expose the animals. I have two ideas, none of which feels satisfactory: 1) Rewrite the code slightly to use shared_ptr instead of a raw ptr and use a middleware that understands s开发者_开发技巧hared_ptr semantics. 2) Generate a "deep lazy proxy" that has the same structure as Animal. Its members would be proxies to members of Animal, recursively. animal_at would be actually called in the last moment before referring to the actual data -- the pointer would be used and immediately tossed away. This would implement the "last moment" semantics.

I dislike 1) because I would have to introduce a "zombie" state of the object, which looks inelegant to me. I dislike 2) because the sole purpose of the proxy is to implement the "last moment" semantics.

I am looking for an automatic non-intrusive way (using code-generation) to achieve this, because I don't want to obscure the meaning of the original code. Is there any "official" name for what I call "last moment" semantics?


There is an option of using boost::weak_ptr. You can pass these around, they have to use lock() to get the underlying shared_ptr so they can see if the object no longer exists.

The lifetime of the object is determined only by the places where a shared_ptr is held. There must therefore be at least one of these at all times during the lifetime of the object, and you need one before you can create a weak_ptr.


Firstly, you might consider xml-rpc instead of CORBA as middleware (more standard use nowadays).

Secondly, external users work with marshalled data. They send a marshalled reference over the middleware and expect marshalled information based on their request and reference, so I don't see how this works together with "last moment" sementics and pointers. You either keep all your temporary animals, so external users can query them or you probably have to send a lot exceptions for not found animals. (or you let them request the "latest" animal)


If your animal_at function returns a pointer that can be invalidated at any point in the future, you might try having it return a smart pointer (I'd suggest a shared_ptr over a weak_ptr here, but you can get away with the weak pointer if you are careful with the implementation). However, instead of pointing directly to an Animal object, have it point to a boost::optional<Animal> object. That way, when you invalidate the pointer, you can set the invalid flag on the pointer and any user of the newly invalidated object have the ability to check to see if they need to get a new pointer.


I don't get why you want to export a pointer instead of exporting an interface which seems exactly the "last moment" semantics that you want. Your animal_at could return an object id, not a pointer, and the interface would give all the required access to the object, like dosomething(id, params). The interface could also include lock/unlock stuff to enable atomic access.

0

精彩评论

暂无评论...
验证码 换一张
取 消