Saturday, May 3, 2014

shared_ptr-2

I've figured out, what was my problem with shared_ptr. The problems there start with using reset(pte) to store a newly constructed object in an existing shared_ptr. Which provokes into using reset(ptr) for storing any pointers. The solution is to never use reset(ptr). Instead either always turn the pointers into shared_ptr first, then assign them. Such as one of:

something->shared_ = make_shared<Object>(args);
something->shared_ = shared_ptr<Object>(new Object(args));

or even make the constructors protected and wrap them into the static methods that would return a shared_ptr.

Which puts shared_ptr close enough to Autoptr. It's still more awkward and less efficient but a potential advantage is that it can handle any object, without the reference counting built into the objects themselves.

A consequence of this approach is that they absolutely need weak_ptr, they can't just have the naked pointers sitting around pointing up the trees, that break sthe whole paradigm. Having the weak references is also convenient if you really need them. But as my experience with Triceps shows, they are generally overrated. Never had to use them for Triceps, and the ptwrap library I use (and wrote) has them!

If used to point up the tree, there is not that much advantage compared to a simple pointer because it's typically easy for the code to just hold that up-the-tree object separately while dealing with it. If used between the peer objects, one of the objects can usually be split into two parts. I.e. If there are objects A and B, B is usually interested not in the whole A but in a part of it. So separate that part into the object C. Then A would refer to B and C, and B would refer to C.

Friday, May 2, 2014

std::shared_ptr

I've tried recently to use the C++11 version of the reference counting, the class std::shared_ptr. And I must say, it's crap. Utter and complete crap.

Their problem is that they are trying to do reference counting to any structures at all, without storing the reference counter in the structure itself. The consequence is that you absolutely can't mix the shared_ptr and pointers. Once you store a pointer in a shared_ptr , you have to refer to it by shared_ptr, and assign the shared_ptr values to each other. If you take a pointer and store it in another shared_ptr, you end up with two reference counters to the same structure, and end up with the memory corruption. And it's way to easy to make this mistake. It's really not usable.

The end result, my Autoref template is way, way, way better and safer to use.

Thursday, May 1, 2014

auto-detecting the file handle class when passing it through the App

I've been editing the documentation for the passing of the file descriptors between threads, and I've realized that there is no need to specify the class of the Perl file handle when it gets loaded from the App. Instead the name of the class can be easily stored along with the file descriptor and then extracted back. So I went and changed the code to do that. The modifications are:

In the App class the method storeFd() takes an extra argument:

$app->storeFd($name, $fd, $className);

The $className specifies the class of the file object. The empty string can be used as a synonym for "IO::Handle", since ref() returns an empty string for the globs of the old-fashioned file handles.

The methods loadFd() and loadDupFd() now return two values:

($fd, $fclass) = $app->loadFd($name);
($fd, $fclass) = $app->loadDupFd($name);

The second returned value is the class name, as it was stored by storeFd().

And the methods App::loadDupSocket(), TrieadOwner::trackDupSocket() and TrieadOwner::trackGetSocket() have been removed. Instead App::loadDupFile(), TrieadOwner::trackDupFile() and TrieadOwner::trackGetFile() have been updated to get the stored file handle class and use it transparently, so they just work correctly for the sockets now.

The methods App::loadDupFileClass(), trieadOwner::trackDupClass() and TrieadOwner::trackGetClass() are still present, in case if you would want to override the class name, but now they should be pretty much never needed, since any class names should be handled automatically without the need for overrides.

And the C++ App class got changed a little bit as well, with the extended versions of storeFd() and loadFd():

void storeFd(const string &name, int fd);
void storeFd(const string &name, int fd, const string &className);
int loadFd(const string &name, string *className = NULL) const;

The new interface is backwards-compatible with the old one but also has the provision for storing and loading the file class name.