[Lemon-user] [Lemon-devel] Array class proposal

Balázs Dezső deba.mf at gmail.com
Fri Jul 27 11:14:46 CEST 2012


> Unfortunately will not. For example
Yes, you are right.

According this article, in the pre c++11 era, the only solution is to
have every parameter combination.
http://msdn.microsoft.com/en-us/library/dd293668.aspx

Balazs

On Thu, Jul 26, 2012 at 7:00 PM, Alpár Jüttner <alpar at cs.elte.hu> wrote:
> Hi,
>
>> >       * The declarations 'T1 t1' in the constructor parameter lists
>> >         should be changed to 'T1 &t1' or 'const T1 &t1'. In fact, both
>> >         versions should be implemented. Even worse, all possible
>> >         combinations of const/non-const parameters should be
>> >         implemented. Any idea how to do it correctly? Maybe a pair of
>> >         recursive call of the constructor having one less parameters?
>> I think, it's enough to have 'T1 &t1', if parameter g is const
>> ListDigraph& then T1 will be evaluated as 'const ListDigraph'.
>
> Unfortunately will not. For example
>
>         class A
>         {
>           int &a,
>           int b;
>         public:
>           A(int &p,int q) : a(p), b(q) {}
>         };
>         ...
>         int x;
>         Array<A> a(12,x,14);
>
> does not work unless the constructor 'T1 &t1, const T2 &t2' is there.
>
> Regards,
> Alpar
>
>>  You can
>> also check c++11 variadic template arguments feature, which can reduce
>> the necessary code. Precompiler metaprogramming could be also used,
>> but the code would be more complex than adding parameters up to N.
>>
>> >       * The way how the memory block is allocated is wrong. Sometimes
>> >         (not always it crashes at the call of delete []. Does anyone
>> >         know how to correctly allocate a memory block which is to be
>> >         deallocated by delete []?
>> >         An alternative is the use std::allocator<>, but it seems to
>> >         increase the memory footprint a bit.
>>
>> I would use char array allocation and deallocation and call the
>> destructor of the items directly:
>> _array = reinterpret_cast<T*>(operator new char[size*sizeof(T)]);
>> delete[] reinterpret_cast<char*>(_array);
>>
>> The problem is with your code that a normal p = new T[n] returns a
>> memory address for which
>> *(reinterpret_cast<int*>(reinterpret_cast<T>(p) - sizeof(T*))) == n
>> (it's not completely true for objects without destructor). So it
>> allocates more memory than you did, and stores the array size in the
>> first word - before the returned pointer. At the delete[] call, it
>> tries to find this size information, which is missing in your
>> implementation. Otherwise, the implementation can be compiler
>> dependent, that's way I would not depend on it, and i would use the
>> char* allocation.
>>
>>
>> You need also handle exceptions in the constructors properly. If one
>> of them breaks, then you have to call the destructor of the already
>> constructed items, and then rethrow the exception.
>>
>> Balazs
>>
>> On Thu, Jul 26, 2012 at 4:06 PM, Alpár Jüttner <alpar at cs.elte.hu> wrote:
>> > Two caveats concerning the array implementation of the previous mail:
>> >
>> >       * The declarations 'T1 t1' in the constructor parameter lists
>> >         should be changed to 'T1 &t1' or 'const T1 &t1'. In fact, both
>> >         versions should be implemented. Even worse, all possible
>> >         combinations of const/non-const parameters should be
>> >         implemented. Any idea how to do it correctly? Maybe a pair of
>> >         recursive call of the constructor having one less parameters?
>> >       * The way how the memory block is allocated is wrong. Sometimes
>> >         (not always it crashes at the call of delete []. Does anyone
>> >         know how to correctly allocate a memory block which is to be
>> >         deallocated by delete []?
>> >         An alternative is the use std::allocator<>, but it seems to
>> >         increase the memory footprint a bit.
>> >
>> > Regards,
>> > Alpar
>> >
>> >
>> > On Thu, 2012-07-26 at 10:24 +0200, Alpár Jüttner wrote:
>> >> Hi,
>> >>
>> >> It is a common problem that one would like use an array of objects, but
>> >> (s)he can't because the object either (a) not default constructible or
>> >> (b) not copyable. Notably, it is a regular question from LEMON users how
>> >> to create an array of NodeMap<>.
>> >>
>> >> If the object is at least default constructible, than you can use
>> >> new[]/delete[], otherwise (such as for NodeMap) the only reasonable
>> >> solution is using std::vector<Object *> and manually and individually
>> >> allocating/deleting the objects.
>> >>
>> >> Note, that even std::array introduced by C++11 fails to solve this
>> >> problem, for (1) its size is determined compile-time, and (2) does not
>> >> resolve (a).
>> >>
>> >> Instead, I propose another Array implementation, please find the
>> >> prototype at the end of this mail.
>> >>
>> >> This is a fixed-size array, but the size is determined run time, i.e. at
>> >> construction. Moreover, the objects in the array are constructed using
>> >> the parameters passed to Array itself. Thus you can do this:
>> >>
>> >>         ListDigraph g;
>> >>         ListDigraph::Node n;
>> >>         ...
>> >>         int size = 12;
>> >>         Array<ListDigraph::NodeMap<int> > map_array(size, g);
>> >>         map_array[2][n]=5;
>> >>         map_array[3][n]+=11;
>> >>
>> >> or even:
>> >>
>> >>         Array<ListDigraph::NodeMap<bool> > map_array(size, g, true);
>> >>         map_array[2][n]=false;
>> >>
>> >> What do you think of this idea? Does it worth including into LEMON?
>> >>
>> >> Plus a design question - do we need the _size member? Omitting it would
>> >> be result in a narrower layer above the simple pointer it actually
>> >> wraps. On the other, it allows a more stl-like interface with size(),
>> >> iterators, begin(), end() etc. But to be honest, I see very little use
>> >> of them here, except for size().
>> >>
>> >> Regards,
>> >> Alpar
>> >>
>> >>
>> >> // *****************************************************
>> >> // * Array class                                       *
>> >> // *****************************************************
>> >>
>> >>   template<class T >
>> >>   class Array {
>> >>     T * _array;
>> >>     size_t _size;
>> >>
>> >>     ///Copying is not allowed.
>> >>     Array(const Array &);
>> >>     ///Copying is not allowed.
>> >>     Array &operator=(const Array &);
>> >>
>> >>   public:
>> >>     explicit Array(size_t size) : _array(new T[size]), _size(size) {}
>> >>     template <class T1>
>> >>     explicit Array(size_t size, T1 t1)
>> >>       : _array( static_cast<T*>(operator new[] (size*sizeof(T)))),
>> >> _size(size)
>> >>     {
>> >>       for(size_t i=0;i<size;i++)
>> >>       new (_array+i) T(t1);
>> >>     }
>> >>     template <class T1, class T2>
>> >>     explicit Array(size_t size, T1 t1, T2 t2)
>> >>       : _array( static_cast<T*>(operator new[] (size*sizeof(T)))),
>> >> _size(size)
>> >>     {
>> >>       for(size_t i=0;i<size;i++)
>> >>       new (_array+i) T(t1,t2);
>> >>     }
>> >>     template <class T1, class T2, class T3>
>> >>     explicit Array(size_t size, T1 t1, T2 t2, T3 t3)
>> >>       : _array( static_cast<T*>(operator new[] (size*sizeof(T)))),
>> >> _size(size)
>> >>     {
>> >>       for(size_t i=0;i<size;i++)
>> >>       new (_array+i) T(t1,t2,t3);
>> >>     }
>> >>     template <class T1, class T2, class T3, class T4>
>> >>     explicit Array(size_t size, T1 t1, T2 t2, T3 t3, T4 t4)
>> >>       : _array( static_cast<T*>(operator new[] (size*sizeof(T)))),
>> >> _size(size)
>> >>     {
>> >>       for(size_t i=0;i<size;i++)
>> >>       new (_array+i) T(t1,t2,t3,t4);
>> >>     }
>> >>     template <class T1, class T2, class T3, class T4, class T5>
>> >>     explicit Array(size_t size, T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
>> >>       : _array( static_cast<T*>(operator new[] (size*sizeof(T)))),
>> >> _size(size)
>> >>     {
>> >>       for(size_t i=0;i<size;i++)
>> >>       new (_array+i) T(t1,t2,t3,t4,t5);
>> >>     }
>> >>
>> >>     ~Array() { delete [] _array; }
>> >>     operator T* () { return _array; }
>> >>     size_t size() { return _size; }
>> >>   };
>> >> }
>> >>
>> >>
>> >> _______________________________________________
>> >> Lemon-devel mailing list
>> >> Lemon-devel at lemon.cs.elte.hu
>> >> http://lemon.cs.elte.hu/mailman/listinfo/lemon-devel
>> >>
>> >>
>> >>
>> >> _______________________________________________
>> >> Lemon-user mailing list
>> >> Lemon-user at lemon.cs.elte.hu
>> >> http://lemon.cs.elte.hu/mailman/listinfo/lemon-user
>> >>
>> >
>> >
>> > _______________________________________________
>> > Lemon-user mailing list
>> > Lemon-user at lemon.cs.elte.hu
>> > http://lemon.cs.elte.hu/mailman/listinfo/lemon-user
>>
>
>



More information about the Lemon-user mailing list