Boost logo

Boost :

Subject: Re: [boost] How to get the size of an C-array?
From: Schrader, Glenn (gschrad_at_[hidden])
Date: 2009-10-15 16:03:25


> -----Original Message-----
> From: boost-bounces_at_[hidden] [mailto:boost-bounces_at_[hidden]]
> On Behalf Of vicente.botet
> Sent: Thursday, October 15, 2009 3:25 AM
> To: boost_at_[hidden]
> Subject: Re: [boost] How to get the size of an C-array?
>
> Hi again,
> ----- Original Message -----
> From: "vicente.botet" <vicente.botet_at_[hidden]>
> To: <boost_at_[hidden]>
> Sent: Thursday, October 15, 2009 8:18 AM
> Subject: Re: [boost] How to get the size of an C-array?
>
>
> >
> > Hi,
> > ----- Original Message -----
> > From: "Schrader, Glenn" <gschrad_at_[hidden]>
> > To: <boost_at_[hidden]>
> > Sent: Wednesday, October 14, 2009 11:43 PM
> > Subject: Re: [boost] How to get the size of an C-array?
> >
> >
> >>
> >>
> >>
> >>> -----Original Message-----
> >>> From: boost-bounces_at_[hidden] [mailto:boost-
> bounces_at_[hidden]]
> >>> On Behalf Of vicente.botet
> >>> Sent: Wednesday, October 14, 2009 4:54 PM
> >>> To: boost_at_[hidden]
> >>> Subject: Re: [boost] How to get the size of an C-array?
> >>>
> >>> Hi Andrey,
> >>> ----- Original Message -----
> >>> From: "Andrey Semashev" <andrey.semashev_at_[hidden]>
> >>> To: <boost_at_[hidden]>
> >>> Sent: Wednesday, October 14, 2009 7:18 PM
> >>> Subject: Re: [boost] How to get the size of an C-array?
> >>>
> >>>
> >>> >
> >>> > vicente.botet wrote:
> >>> >> Hi,
> >>> >>
> >>> >> On TBoost.STM, I need to do something before deleting an array on
> each
> >>> one of the elements of the array, or more precissely with the address
> of
> >>> each one of the elements.
> >>> >>
> >>> >> T* ptr = new T[3];
> >>> >>
> >>> >> // in another file, the number of elements to which ptr points is
> >>> unknown.
> >>> >> // before deleting
> >>> >> for (size_t i=0; i< 'ptr size'; ++i) {
> >>> >> // do something with &ptr[i]
> >>> >> }
> >>> >> delete [] ptr;
> >>> >>
> >>> >> As the number of elemenst is unknow in the separated unit, I have
> no
> >>> mean to iterate on ptr to get the address of the elements.
> >>> >>
> >>> >> The C++ compiler or the C++ standard library knows this number of
> >>> elements as it needs to call the destructor of each element when
> deleting
> >>> the pointer. Is there something in Boost or a portable way to recover
> the
> >>> number of elements of the array, maybe overloading the new [] operator
> and
> >>> prefixing the allocate storage with some information? But what
> information
> >>> can be stored so the implementation is portable?
> >>> >
> >>> > There is no portable way to acquire the dynamic array length. IMO,
> there
> >>> > are two practical solutions for this:
> >>> >
> >>> > 1. Put everything you need into T's destructor. If T is a third
> party
> >>> > type then a wrapper class around T can serve the purpose.
> >>>
> >>> Well, the problem is that we need to do something before the
> destructor is
> >>> called. When deleting an array of transactional objects we need to
> mark
> >>> each one of the elements as if they were written, so the conclict
> >>> detection cat detect other threads been written on a specific array
> >>> element.
> >>>
> >>> > 2. Use a range wrapper instead of a raw pointer to the array.
> >>>
> >>> This is equivalent to say that we can not use dynamic arrays with the
> STM
> >>> library. Before to abandoning I want to explore all the posibilities.
> >>>
> >>> > Regarding the trick with the prepended length storing, it can solve
> the
> >>> > problem, but it introduces pointer magic which may not be obvious
> for
> >>> > the ones reading the code (including yourself a couple months
> later).
> >>> > And, AFAIK, you won't be able to override the standard new and
> delete
> >>> > operators to behave that way, so you'll have to use dedicated
> functions
> >>> > to allocate/deallocate such arrays. Therefore I wouldn't recommend
> it
> >>> > unless there are significant reasons for it.
> >>>
> >>> No, I don't want to overload the standard new and delete operators,
> just
> >>> provide a mixing helping the user to define transactional objects. For
> >>> these transactional objects, the overload of the operator new and
> new[]
> >>> could set some information that will allow us to define a free
> function
> >>> size taking a transactional object pointer and returning its size. The
> >>> drawback of using specific functions is that we will need to educate
> the
> >>> user, and yet more important, we couldn't use generic classes that
> make
> >>> use of these standard operators, as e.g. auto_ptr or scoped_ptr.
> >>>
> >>> The problem I find overloading new[] is that I dont know where my
> prefixed
> >>> information will be placed respect to the returned pointer, as the
> >>> standard, prefix it already to store its own specific information.
> >>>
> >>> pointer returned by new[]
> >>> |
> >>> v
> >>> | my_prefic | std prefix | user area |
> >>>
> >>> The parameter size_t of the new[] operator is the addition of sizes of
> std
> >>> prefix and the user area.
> >>>
> >>> While writing these lines, I think that maybe the size of std prefix
> can
> >>> be calculated requesting the creation of an array with only one
> element,
> >>> so we can calculate the
> >>>
> >>> sizeof(std prefix) = requested size for new T[1] - sizeof(T)
> >>>
> >>> Does this make sens? Would this be portable?
> >>
> >> Somehow, you need to guarantee that the memory address of the start of
> the
> >> memory area is aligned properly for objects of type T, otherwise all of
> the
> >> elements in the array will be misaligned. Different architectures often
> >> have different alignment requirements.
> >
> > Yes, I must consider alignement.
> >
> >> Also, consider the following:
> >> {
> >> T v[3];
> >> T* p=&v[0];
> >> int s = size(p); // undefined behavior
> >> }
> >
> > Very good observation. Unfortunately, I don't think I could do nothing
> in this case. Is there a way to check if a pointer has been allocated
> dynimically?
>
> Well I suspect the answer is no.
>
> In my opinion, this should be undefined behavior as it is the case for
>
> T v[3];
> T* p=&v[0];
> delete p; // undefined behavior
>
> In addition, I don't need to make public this function, as I need it only
> internally.
> Maybe I could do something similar to the boost::extent metafunction:
>
> template <typename T, std::size_t N = 0>
> struct number_of_elements {
> ...
> };
>
> but number_of_elements will work as boost::extent except when the result
> of extent is 0. In this case the metafunction suposse that the given
> pointer has been allocated with the overloaded new[]. If it is not the
> case the result will be undefined.
>
> Do you consider that this metafunction is coherent?
>
> Can someone in this list explain why the standard don't allows to recover
> the number of elements allocated by new[]? What is the deep reason?
>
> Best regards,
> Vicente

I don't know why but the same thing shows up elsewhere. For instance I
don't know of a way to query the size of a memory block that was
allocated with malloc() either. Even so, this isn't a major problem
since its easy enough to create smart pointers that store the extra
information. That also avoids burdening the infrastructure with things
that many people may not care about under the "you only pay for what
you use" C/C++ mantra.

Tacking extra information onto the front of an array like you're doing
above can be made to work. In fact, some (most??) malloc() and free()
implementations manage their heap memory in a similar manner (e.g. using
linked lists of allocated blocks and free blocks). You might get a sense
of how portably this can be done by looking through the GNU implementation
of malloc and free and see what they needed to do to support different
platforms.

There really isn't a safe way to do this using simple pointers
so I use smart pointers quite a lot although in your case though I
would also consider a std::vector.

--glenn


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk