Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Element of shared_array as shared_ptr?

If I have a boost::shared_array<T> (or a boost::shared_ptr<T[]>), is there a way to obtain a boost::shared_ptr<T> which shares with the array?

So for example, I might want to write:

shared_array<int> array(new int[10]);
shared_ptr<int> element = &array[2];

I know that I can't use &array[2], because it just has type int *, and it would be dangerous for shared_ptr<int> to have an implicit constructor that will take that type. Ideally shared_array<int> would have an instance method on it, something like:

shared_ptr<int> element = array.shared_ptr_to(2);

Unfortunately I can't find anything like this. There is an aliasing constructor on shared_ptr<int> which will alias with another shared_ptr<T>, but it won't allow aliasing with shared_array<T>; so I can't write this either (it won't compile):

shared_ptr<int> element(array, &array[2]);
//Can't convert 'array' from shared_array<int> to shared_ptr<int>

Another option I played with was to use std::shared_ptr<T> (std instead of boost). The specialisation for T[] isn't standardised, so I thought about defining that myself. Unfortunately, I don't think that's actually possible in a way that doesn't break the internals of the aliasing constructor, as it tries to cast my std::shared_ptr<T[]> to its own implementation-specific supertype, which is no longer possible. (Mine is currently just inheriting from the boost one at the moment.) The nice thing about this idea would have been that I could implement my instance shared_ptr_to method.

Here's another idea I experimented with, but I don't think it's efficient enough to be acceptable as something we're potentially going to use throughout a large project.

template<typename T>
boost::shared_ptr<T> GetElementPtr(const boost::shared_array<T> &array, size_t index) {
    //This deleter works by holding on to the underlying array until the deleter itself is deleted.
    struct {
        boost::shared_array<T> array;
        void operator()(T *) {} //No action required here.
    } deleter = { array };
    return shared_ptr<T>(&array[index], deleter);
}

The next thing I'm going to try is upgrading to Boost 1.53.0 (we currently only have 1.50.0), using shared_ptr<T[]> instead of shared_array<T>, and also always using boost instead of std (even for non-arrays). I'm hoping this will then work, but I haven't had a chance to try it yet:

shared_ptr<int[]> array(new int[10]);
shared_ptr<int> element(array, &array[2]);

Of course I'd still prefer the instance method syntax, but I guess I'm out of luck with that one (short of modifying Boost):

shared_ptr<int> element = array.shared_ptr_to(2);

Anyone else have any ideas?

like image 495
entheh Avatar asked Mar 21 '13 13:03

entheh


1 Answers

You are doing strange stuff. Why do you need shared_ptr to element? Do you want element of array be passed somewhere else and hold down your array from removal?

If yes, than std::vector<shared_ptr<T>> is more suited for that. That solution is safe, standard and has fine granularity on objects removal

like image 85
kassak Avatar answered Oct 02 '22 08:10

kassak