Subject: Re: [boost] [shared_array] Why not in C++11 ?
From: Rob Stewart (robertstewart_at_[hidden])
Date: 2013-07-08 05:49:31
On Jul 8, 2013, at 4:21 AM, Andrey Semashev <andrey.semashev_at_[hidden]> wrote:
> On Mon, Jul 8, 2013 at 11:59 AM, Sid Sacek <ssacek_at_[hidden]> wrote:
>> My original thought was to make 'size' a requirement for shared_ptr< T > since why
>> would anyone use an array without knowing the array's bounds ? Every array has bounds and nobody would touch an array without knowing that information. And placing that information with the array itself makes the most sense to me.
> Size could be implied from other components around the pointer. E.g.
> you could have multiple buffers of the same size encapsulated in a class that maintains this invariant.
That's a very limiting view.
>> If it were made a requirement, then the code might look something like this, or
>> something even more clever:
>> shared_ptr< char > buffer( new char[ 10 ], 10 );
>> The above constructor would set the capacity value to 10. If however, the coder were to simply do this:
>> shared_ptr< char > buffer( new char[ 10 ] );
>> It is clear that the coder has no interest in the capacity information for the buffer,
>> and therefore no other part of that programmer's code will be looking for it either.
>> This would be a non-breaking change, since that is the default behavior of shared_ptr<T>, and the capacity could simply be set to 0.
That's error-prone. Why not provide (non-zero) capacity when using make_shared(), and leave the non-make_shared() usage with a zero capacity? That will encourage the use of make_shared() and avoid mistakes.
> While that looks feasible, I still would prefer to use a container
> over a pointer in this case. Providing size manually is error prone at least.
A container is better than manually specifying the capacity, but it isn't shared.
>> Let me describe how this feature could be used. Imagine your socket library filled user
>> buffers as data arrived. For example:
>> socket::fill_buffer( shared_ptr<char> buffer )
>> my_socket-> fill_buffer( my_buffer );
>> In this case, your library doesn't simply want a shared buffer pointer, but it also needs
>> to know where the buffer ends. Of course you could specify that with extra arguments, which is how it has traditionally been done in C, but with buffer objects, the buffer pointer and
>> its size will be kept atomic. That could prevent buffer overflow bugs from occurring.
> With manual size provision this is still asking for trouble, IMHO.
> Just use a plain vector and forget about buffer overruns or
> insufficient buffer sizes.
> In fact, you don't share anything here, so by using vector you express your intent more clearly. You may argue about copying the buffer contents or asynchronous operation execution, but move semantics helps here.
Move semantics won't help with async use cases.
>> The buffer object no longer behaves like a regular shared_ptr<>, but behaves very much like an array, and for all intents and purposes, it is an array, it is a buffer! What I mean is, it is not a pointer anymore, and you can no longer do this:
>> buffer-> ???? // what can the pointer operator be used for ????
> The operator-> would work like with any raw pointer - it would return a pointer to the first element of the array.
His point is that, without at least knowing the capacity, code called with a shared_ptr<T> cannot use it because the extent is unknown.
> Specializing the interface based on the template argument is not intuitive, IMHO.
We have that already with the subscript operator.
Arguably, having only capacity() is insufficient. For cases in which the full extent is not available, size() would be wanted. Where does this end? How many other member functions are needed to cover all reasonable use cases?
Perhaps the shared container idea has merit. After all, shared_ptr<T> does ensure delete is called, and adding capacity() would provide all original information.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk