Multi-dimensional array allocation with single 'new' call

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • ip4ram@yahoo.com

    Multi-dimensional array allocation with single 'new' call

    I used to work with C and have a set of libraries which allocate
    multi-dimensional arrays(2 and 3) with single malloc call.

    data_type **myarray
    = (data_type**)ma lloc(widht*heig ht*sizeof(data_ type)+ height*
    sizeof(data_typ e*));

    //allocate individual addresses for row pointers.

    Now that I am moving to C++,am looking for something by which I can
    allocate a
    multi-dimensional array with one (and only one) 'new' call.

    Does my old libraries (with malloc calls) work in C++.Yes.

    Then why do I want to use 'new'.Some books encourage usage of new to
    malloc(I assume new is much safer than malloc). Anyways,can this be
    done?Has anybody done it ?

    Thanks,in advance, for all your help.

    Ram
  • Gianni Mariani

    #2
    Re: Multi-dimensional array allocation with single 'new' call

    ip4ram@yahoo.co m wrote:[color=blue]
    > I used to work with C and have a set of libraries which allocate
    > multi-dimensional arrays(2 and 3) with single malloc call.
    >
    > data_type **myarray
    > = (data_type**)ma lloc(widht*heig ht*sizeof(data_ type)+ height*
    > sizeof(data_typ e*));
    >
    > //allocate individual addresses for row pointers.
    >
    > Now that I am moving to C++,am looking for something by which I can
    > allocate a
    > multi-dimensional array with one (and only one) 'new' call.
    >
    > Does my old libraries (with malloc calls) work in C++.Yes.
    >
    > Then why do I want to use 'new'.Some books encourage usage of new to
    > malloc(I assume new is much safer than malloc). Anyways,can this be
    > done?Has anybody done it ?
    >
    > Thanks,in advance, for all your help.[/color]

    In C++, you don't need any new calls. Consider this:

    #include <vector>

    template <typename w_elem_type>
    class matrix
    {
    public:
    typedef int t_Size;

    t_Size m_columns;
    t_Size m_rows;

    std::vector<w_e lem_type> m_data;

    matrix( t_Size i_columns = 0, t_Size i_rows = 0 )
    : m_columns( i_columns ),
    m_rows( i_rows ),
    m_data( i_columns * i_rows )
    {
    }

    w_elem_type * operator[]( t_Size i_index )
    {
    return & ( m_data[ i_index * m_rows ] );
    }

    template <typename w_Type, int w_columns, int w_rows>
    matrix( const w_Type (&i_array)[w_columns][w_rows] )
    : m_columns( w_columns ),
    m_rows( w_rows ),
    m_data( & (i_array[0][0]), & (i_array[w_columns-1][w_rows]) )
    {
    }

    };



    #include <iostream>

    double array[3][4] = {
    { 1.0, 2.0, 3.3, 4.4 },
    { 1.0, 2.0, 3.3, 4.4 },
    { 1.0, 2.0, 3.3, 4.5 },
    };

    int main()
    {
    matrix<float> mat1( 3, 4 );
    matrix<float> mat2;
    // convert a double array to a float matrix (on the fly!)
    matrix<float> mat3( array );

    mat2 = mat3;

    std::cout << mat2[2][3] << "\n";
    }


    How would you do this with malloc ?

    Comment

    • Dietmar Kuehl

      #3
      Re: Multi-dimensional array allocation with single 'new' call

      ip4ram@yahoo.co m wrote:[color=blue]
      > I used to work with C and have a set of libraries which allocate
      > multi-dimensional arrays(2 and 3) with single malloc call.
      >
      > data_type **myarray
      > = (data_type**)ma lloc(widht*heig ht*sizeof(data_ type)+ height*
      > sizeof(data_typ e*));[/color]

      Note that you are allocating two separate data structures at once:
      - the data area for your multi-dimensional array
      - an array of pointers to the beginning of the rows

      I assume you are then computing and storing the start addresses of the
      individual rows. Without measuring the effect, I would actually guess
      that the on-the-fly computation of the addresses is not slower than the
      pointer look-up. In C++ this can neatly be encapsulated by a suitable
      function of an multi-dimensional array class. This is just a separate
      issue you might want to consider.
      [color=blue]
      > Now that I am moving to C++,am looking for something by which I can
      > allocate a multi-dimensional array with one (and only one) 'new' call.[/color]

      It is important to understand the motivation of replacing 'malloc()' by
      'new': other than 'malloc()', 'new' calls the constructor of the
      respective objects. For POD-types (ie. for built-in types and C-like
      structs), this actually does nothing (... and the calls to any form of
      constructors are elided, ie. it is in no way a performance hit) but for
      class types the necessary initialization is performed. You can use
      'malloc()' or its moral C++ equivalent, ie. 'operator new()' or
      'operator new[]()', in C++, too, but you have to make sure to call the
      relevant constructors and, at destruction time, the relevant
      destructors.
      [color=blue]
      > Does my old libraries (with malloc calls) work in C++.Yes.[/color]

      Considering my previous paragraph, I would seriously question your
      statement that use of 'malloc()' works properly - unless you are only
      using multi-dimensional arrays with POD-types in which case there is
      no good reason to rewrite your library to use 'new', IMO.
      [color=blue]
      > Then why do I want to use 'new'.Some books encourage usage of new to
      > malloc(I assume new is much safer than malloc).[/color]

      Understanding the motivation of any advice is quite important to
      understand when to follow the advice. 'new' is no way "safer" than
      'malloc()'. For non-POD types 'malloc()' without later explicit
      constructor calls (see below) simply does not work!
      [color=blue]
      > Anyways,can this be done?Has anybody done it ?[/color]

      The answers to these questions are "kind of" and "yes". The purpose of
      using 'new' is to invoke the constructors for the objects. Likewise,
      the purpose of 'delete' is to invoke the destructors for the objects.
      That is, in addition to the memory management operations, of course.
      Although C++ does not provide an immediate approach to the creation of
      inhomogenous areas of memory, it provides a manual approach under the
      name of "placement new". The idea is to split the operation into its
      two components:

      - memory management (memory allocation of 'new' and memory release for
      'delete')
      - object life-time maintenance, ie. construction of 'new' and
      destruction for 'delete'.

      Whether you are using 'operator new()' and 'operator delete()' (or, if
      you prefe, 'operator new[]()' and 'operator delete[]()') or 'malloc()'
      and 'free()' for the memory management, does not really matter. However,
      you need to use placement-new and placement-delete for the other
      component.

      Here is some code to illustrate this (normally, this code would be
      encapsulated into an appropriate class):

      // header for placement-new function:
      #include <new>

      // obtain the memory with just one call:
      void* mem = operator new(width * height * sizeof(data_typ e)
      + height * sizeof(data_typ e*));

      // initialize the data area:
      data_type* array = static_cast<dat a_type*>(mem);
      // the C++ approach to initialization is actually this:
      // std::uninitiali zed_fill(array, width * height, data_type());
      // ... but for demonstraction here is a similar, though semantically
      // slightly different approach (*):
      for (data_type* cur = array, end = array + width * height;
      cur != end; ++cur)
      new(cur) T();

      // initialize the row pointers:
      typedef data_type* data_type_ptr; // (**)
      data_type** rows = reinterpret_cas t<data_type**> (
      reinterpret_cas t<char*>(mem) + width * height * sizeof(data_typ e);
      for (std::size_type i = 0; i != height; ++i)
      new(rows[i]) data_type_ptr(a rray + i);

      // use the array

      // destroy the row pointers:
      for (std::size_type i = height; --i; )
      row[i].~data_type_ptr ();

      // destroy the data area:
      for (data_type* cur = array + width * height; array != cur; )
      (--cur)->~data_type() ;

      // release the memory:
      operator delete(mem);

      Comments:
      * The semantic difference is that 'uninitialized_ fill()' uses the
      copy constructor on the passed object while the explicit loop
      uses the default constructor for each object.
      ** I'm not sure whether this typedef is necessary for the construction
      (I think it is not) but it is necessary for the destruction.

      Conclusions:
      - Yes, it is possible.
      - I don't think it is worth the hassel:
      - the array of row pointers is probably only good to decrease
      performance, both during construction and use
      - even if you insist in using this array, it is easier to use
      multiple allocations and I seriously doubt that you will be
      able to measure the difference for any reasonable sized array.
      --
      <mailto:dietmar _kuehl@yahoo.co m> <http://www.dietmar-kuehl.de/>
      <http://www.contendix.c om> - Software Development & Consulting

      Comment

      Working...