delete[] p or delete[] *p

Discussion in 'C++' started by Paul, Mar 27, 2011.

  1. Paul

    Paul Guest

    Hi,
    Suppose I have the following code:

    int (*p)[5] = (int (*)[5])new int[5];

    How do I delete the allocated memory?
    Is it:
    a) delete[] p;
    b) delete[] *p;
    c) delete[] (int*)p;

    ?? Any ideas??
    Paul, Mar 27, 2011
    #1
    1. Advertising

  2. On Mar 26, 10:21 pm, cg_chas <> wrote:
    > On Sun, 27 Mar 2011 01:19:37 -0400, cg_chas <> wrote:
    > >On Sun, 27 Mar 2011 05:34:51 +0100, "Paul" <> wrote:

    >
    > >>Hi,
    > >>Suppose I have the following code:

    >
    > >>int (*p)[5] = (int (*)[5])new int[5];

    >
    > >>How do I delete the allocated memory?
    > >>Is it:
    > >>a) delete[] p;
    > >>b) delete[] *p;
    > >>c) delete[] (int*)p;

    >
    > >>?? Any ideas??

    >
    > >You have casted the pointer type returned from new into a different pointer, but
    > >regardless, new allocated an array of 5 ints, so you call delete [] on the
    > >pointer that new returned.

    >
    > my correction: should say  you have casted the pointer type returned from new
    > into a different pointer "type"


    I'd like to point out that AFAIK the first cast may result in a loss
    of information. You're only guaranteed round-way trips through void*,
    char*, and unsigned char*, (and an integer type of sufficient size).
    Thus the delete[] could be UB on a conforming platform. That's right,
    right?
    Joshua Maurice, Mar 27, 2011
    #2
    1. Advertising

  3. Paul

    Öö Tiib Guest

    On Mar 27, 7:34 am, "Paul" <> wrote:
    > Hi,
    > Suppose I have the following code:
    >
    > int (*p)[5] = (int (*)[5])new int[5];
    >
    > How do I delete the allocated memory?
    > Is it:
    > a) delete[] p;
    > b) delete[] *p;
    > c) delete[] (int*)p;
    >
    > ?? Any ideas??


    I think that c) but why you reinterpret_cast at first place?

    I start to wonder do you ever use raw dynamic arrays and if then why
    do you use them? I don't. In C code I do but there are allocated with
    malloc() and deallocated with free(). Usage of "delete[]" itself
    usually indicates that some novice in team has copy-pasted something
    cheesy from google or from a book into our code base.

    In C++ it is often clear how a particular container of T's should be
    used (as stack or as set or as queue or as vector). Sometimes it is
    unclear. I usually take std::vector<T> first when it is unsure how
    container will be used. Later it settles and usually it remains as
    such for ages after.

    Sometimes very rarely it later becomes apparent that a container
    causes performance or maintainability issues related to nature or
    usage of it. Then i revisit what exact underlying container type is
    used. Refactoring vector into some other container may make sense at
    that spot.

    The chosen type depends on what is done with container and what is not
    done with it. There are so lot of somewhat similar to vector
    containers to choose. boost::array<T>, boost::scoped_array<T>,
    std::map<int,T>, std::list<T>, boost::intrusive::slist<T> and so on.
    Basically ... just describe exact nature and usage of container and no
    doubt that there is very close template available and free to use.
    Vector may become even raw static array, but i see no reasons to use
    raw dynamic array in C++.

    Raw static arrays i use for static tables. Sometimes initial
    requirements described some "list" of information and vector was
    chosen and later it did appear that it is actually static table of
    information. There is so elegant (IMHO) syntax for initializing static
    arrays in C so it is lot better to maintain. Like i understand C++0x
    will allow using such syntax for initializing other containers as
    well.
    Öö Tiib, Mar 27, 2011
    #3
  4. Paul

    Kai-Uwe Bux Guest

    Joshua Maurice wrote:

    > On Mar 26, 10:21 pm, cg_chas <> wrote:
    >> On Sun, 27 Mar 2011 01:19:37 -0400, cg_chas <> wrote:
    >> >On Sun, 27 Mar 2011 05:34:51 +0100, "Paul" <>
    >> >wrote:

    >>
    >> >>Hi,
    >> >>Suppose I have the following code:

    >>
    >> >>int (*p)[5] = (int (*)[5])new int[5];

    >>
    >> >>How do I delete the allocated memory?
    >> >>Is it:
    >> >>a) delete[] p;
    >> >>b) delete[] *p;
    >> >>c) delete[] (int*)p;

    >>
    >> >>?? Any ideas??

    >>
    >> >You have casted the pointer type returned from new into a different
    >> >pointer, but regardless, new allocated an array of 5 ints, so you call
    >> >delete [] on the pointer that new returned.

    >>
    >> my correction: should say you have casted the pointer type returned from
    >> new into a different pointer "type"

    >
    > I'd like to point out that AFAIK the first cast may result in a loss
    > of information. You're only guaranteed round-way trips through void*,
    > char*, and unsigned char*, (and an integer type of sufficient size).
    > Thus the delete[] could be UB on a conforming platform. That's right,
    > right?


    That depends on:

    a) which cast is used and
    b) what the alignment requirement for the involved types are.

    According to [5.2.10/7] you can reinterpret_cast round trip from T1* to T2*
    and back provided the alignment of T2 are not stricter than the ones for T1.

    To me, the C-style cast within the expression

    (int (*)[5]) new int[5]

    looks like a reinterpret_cast. Thus, [5.2.10/7] applies. As to whether
    int[5] may have stricter alignment requirements than int, I think the
    standard remains silent.


    Best,

    Kai-Uwe Bux
    Kai-Uwe Bux, Mar 27, 2011
    #4
  5. Paul

    Paul Guest


    >"Öö Tiib" <> wrote in message
    >news:...
    >On Mar 27, 7:34 am, "Paul" <> wrote:
    >> Hi,
    >> Suppose I have the following code:
    >>
    >> int (*p)[5] = (int (*)[5])new int[5];
    >>
    >> How do I delete the allocated memory?
    >> Is it:
    >> a) delete[] p;
    >> b) delete[] *p;
    >> c) delete[] (int*)p;
    >>
    >> ?? Any ideas??

    >
    >I think that c) but why you reinterpret_cast at first place?
    >

    To convert the dynamic array into an array object type, that would decay
    into a pointer that carried size information, for example:

    template<typename T, int S, typename U= T (&)>
    class R{
    public:
    R():pp((int (*))new int[S+1]), r(*(pp+1)){r[-1]=S;}
    U getArray(){return r;}
    void delete_it(){ delete[] (int*)pp; }
    private:
    int (*pp);
    T (&r);
    };

    template<typename T>
    void foo(T r){
    std::cout<<"size of array:\t" << r[-1];
    std::cout<< "\ntype of array:\t" << typeid(T).name();
    }

    int main() {
    R<int, 7> r;
    int (&r1)[7] = r.getArray();
    foo(r.getArray());
    std::cout<<"\ntype of r1:\t"<< typeid(r1).name();

    r.delete_it();
    }

    >I start to wonder do you ever use raw dynamic arrays and if then why
    >do you use them? I don't. In C code I do but there are allocated with
    >malloc() and deallocated with free(). Usage of "delete[]" itself
    >usually indicates that some novice in team has copy-pasted something
    >cheesy from google or from a book into our code base.


    OFC dynamic arrays are very usefull , especially if creating a specialised
    container.

    >In C++ it is often clear how a particular container of T's should be
    >used (as stack or as set or as queue or as vector). Sometimes it is
    >unclear. I usually take std::vector<T> first when it is unsure how
    >container will be used. Later it settles and usually it remains as
    >such for ages after.


    std::vector is not always the best solution for use within specialised class
    designs. I don't see std::vector as a replacement for dynamic arrays, its a
    good quick and easy solution if you need a basic resizeable vector with safe
    some built in safety.

    >Sometimes very rarely it later becomes apparent that a container
    >causes performance or maintainability issues related to nature or
    >usage of it. Then i revisit what exact underlying container type is
    >used. Refactoring vector into some other container may make sense at
    >that spot.


    I think in C++ we have the power to create a wide variety of specialised
    types, data records etc. I don't like to think that there is a certain
    limited amount of types, defined by the std lib , that we should use.

    >The chosen type depends on what is done with container and what is not
    >done with it. There are so lot of somewhat similar to vector
    >containers to choose. boost::array<T>, boost::scoped_array<T>,
    >std::map<int,T>, std::list<T>, boost::intrusive::slist<T> and so on.
    >Basically ... just describe exact nature and usage of container and no
    >doubt that there is very close template available and free to use.
    >Vector may become even raw static array, but i see no reasons to use
    >raw dynamic array in C++.


    I prefer to design my own type for a spefic need, if there is a something
    suitable in the std lib then great I will use it. but often they are just
    not perfectly suited to the job.


    >Raw static arrays i use for static tables. Sometimes initial
    >requirements described some "list" of information and vector was
    >chosen and later it did appear that it is actually static table of
    >information. There is so elegant (IMHO) syntax for initializing static
    >arrays in C so it is lot better to maintain. Like i understand C++0x
    >will allow using such syntax for initializing other containers as
    >well.


    You are probably basing your views on personal experience as many of us do.
    One of the major attractions to C++ , for me , is the ability to easily
    create specialised types whereas assembly its a bit more complex, I like to
    use this feature of the language often , and I get much satisfaction from
    doing so.
    As you may have guessed I am no big fan of the std lib, I do like some of
    the template features but generally I don't bother with it unless it suits
    the job perfectly.
    AFAIK boost multi-array, and I don't think this is part of the std lib, is
    the closest thing to my needs and its a bit overkill tbh.

    Also learning about different ways of allocating memory is usefull for
    learning purposes and enhances your programming skills, sometimes I prefer
    to invoke the OS's API directly for memory allocation simply to become more
    familiar with the API.

    HTH
    Paul.
    Paul, Mar 27, 2011
    #5
  6. On Mar 27, 5:34 am, "Paul" <> wrote:
    > [Suppose I have the following code:
    >
    > int (*p)[5] = (int (*)[5])new int[5];
    >
    > How do I delete the allocated memory?


    As your question has been answered elsewhere, I'll just add an
    interesting aside from a language design perspective. If C++ had a
    more regular design the type of the "new int [5]" expression would not
    degenerate to "int*". A regular design would render the array
    overloads of new and delete superfluous, and make your cast here
    unnecessary. Consider the irregularity of:

    typedef struct {int a, b, c, d, e;} Struct; // aggregate type
    typedef int Array [5]; // aggregate type
    Struct* ps = new Struct; // Ok!
    Array* pa = new Array; // Error! Should be "int* pa".
    delete ps; // Ok!
    delete pa; // Error! Should be "delete [] pa".

    If instead C++ was regular and this was correct code, the type of the
    pointer would carry the size information and allow the regular delete
    operator to release the correct amount of memory. These irregularities
    are avoided by std::array:

    typedef std::array <int, 5> Array; // aggregate type
    Array* pa = new Array; // Ok!
    delete pa; // Ok!

    Dereferencing the pointer, (*pa), gives you a reference (lvalue) to
    the array as a whole, and an indexing operator is implemented for the
    array class itself (not via degeneration into pointer arithmetic).

    The new std::array circumvents the numerous irregularities between
    pointers and arrays that causes so much confusion. I.e. you can copy
    arrays, pass and return arrays by value to and from functions, and the
    array will never implicitly convert to a pointer to the first element.
    Hence I recommend its use instead of C-style arrays.

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Mar 27, 2011
    #6
  7. Paul

    Goran Guest

    On Mar 27, 6:34 am, "Paul" <> wrote:
    > Hi,
    > Suppose I have the following code:
    >
    > int (*p)[5] = (int (*)[5])new int[5];
    >
    > How do I delete the allocated memory?
    > Is it:
    > a) delete[] p;
    > b) delete[] *p;
    > c) delete[] (int*)p;


    d) when you allocate memory using new T[], you use delete [], passing
    it a T* returned to you by a prior cal to "new T[]". This is how new/
    delete are supposed to work. You broke that with your casts, which is
    the original sin of this code.

    I would guess that all of a, b, and c will work on many
    implementations, but I know of no guarantee for that. One can imagine
    an implementation with bounds-checking where such code fails badly.

    Your "R" example further down makes little sense, perhaps you should
    have given it a bit more of thought. (E.g. what's with r[-1] = S, that
    requires that T has operator=(int) or something, and S is a compile-
    time constant anyhow!?)

    Did you mean to create a variant of the old C trick with size,
    followed by an array of struct, where size is a run-time value? There
    was a +/- heated discussion some time ago about this here, somebody
    made one half-decent C++ implementation then. (No conversion to an
    array though, that wasn't the discussion's goal).

    Goran.
    Goran, Mar 28, 2011
    #7
  8. Paul

    SG Guest

    On 27 Mrz., 20:58, Vidar Hasfjord wrote:
    > [...]
    > unnecessary. Consider the irregularity of:
    >
    >   typedef struct {int a, b, c, d, e;} Struct; // aggregate type
    >   typedef int Array [5]; // aggregate type
    >   Struct* ps = new Struct; // Ok!
    >   Array* pa = new Array; // Error! Should be "int* pa".
    >   delete ps; // Ok!
    >   delete pa; // Error! Should be "delete [] pa".
    >
    > If instead C++ was regular and this was correct code, the type of the
    > pointer would carry the size information and allow the regular delete
    > operator to release the correct amount of memory.


    For the size to be part of the pointer _type_ this size must be a
    compile-time constant. But new[] does not require a compie-time
    constant for the number of elements:

    void foo(int x) {
    new int[x]; // x is not a compile-time constant
    }

    So, the current new[] operator can do something that you can't emulate
    with "new array<T,N>" properly.

    Perhaps an alternate syntax would have been better and more regular:

    void foo(int x)
    {
    int *p = new[x] int; // not real C++ code (unfortunately)
    delete[] p;

    int (*q)[5] = new int[5]; // not real C++ code (unfortunately)
    delete q;
    }

    Anyhow, I consider new[]/delete[] and raw arrays to be nearly useless.
    We have better alternatives and soon get some more: vector<T>,
    array<T,N>, unique_ptr<array<T,N>>, for example. So, "fixing" arrays
    and new[] w.r.t. regularity wouldn't buy you much. You'd mainly lose
    compatibility with old code.

    my 2 cents,
    SG
    SG, Mar 28, 2011
    #8
  9. On Mar 28, 12:25 pm, SG <> wrote:
    > For the size to be part of the pointer _type_ this size must be a
    > compile-time constant. But new[] does not require a compie-time
    > constant for the number of elements: [...]


    Good point. But, if C++ was regular it would require the size to be a
    compile-time constant; as it does everywhere else in the language
    where an array type is expressed. I.e. the argument to new would
    simply be a regular type expression.

    The unrelated use of square brackets to specify a run-time argument is
    highly irregular. And, more over, with templates in the language it is
    unnecessary. Dynamic allocation can be implemented as a library
    function. All you need is a low-level memory allocation function
    (malloc) and placement-new (or a similar construct to allow you to
    construct an object in allocated memory). E.g.

    template <class T> T* construct (size_t n = 1); // replaces new
    template <class T> void destruct (T*); // replaces delete

    > Anyhow, I consider new[]/delete[] and raw arrays to be nearly useless.
    > We have better alternatives and soon get some more: vector<T>,
    > array<T,N>, unique_ptr<array<T,N>>, for example.


    Agree. C++ programmers, except those dealing with legacy code or
    implementing the standard library, can now avoid these irregularities.

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Mar 28, 2011
    #9
  10. On 28 mar, 15:29, Vidar Hasfjord <> wrote:
    > On Mar 28, 12:25 pm, SG <> wrote:
    >
    > > For the size to be part of the pointer _type_ this size must be a
    > > compile-time constant. But new[] does not require a compie-time
    > > constant for the number of elements: [...]

    >
    > Good point. But, if C++ was regular it would require the size to be a
    > compile-time constant; as it does everywhere else in the language
    > where an array type is expressed. I.e. the argument to new would
    > simply be a regular type expression.
    >
    > The unrelated use of square brackets to specify a run-time argument is
    > highly irregular.


    This seems contradictory, the irregularity of array with runtime size
    is AFAIS intended for providing a regular type expression syntax to
    use with new operator.

    > And, more over, with templates in the language it is
    > unnecessary. Dynamic allocation can be implemented as a library
    > function. All you need is a low-level memory allocation function
    > (malloc) and placement-new (or a similar construct to allow you to
    > construct an object in allocated memory). E.g.
    >
    >   template <class T> T* construct (size_t n = 1); // replaces new
    >   template <class T> void destruct (T*); // replaces delete


    And how do you handle constructor parameters for non-array
    initialisation ?
    For a workable solution, you would need perfect forwarding which isn't
    yet standard.

    Moreover, this means that unless you standardise it, every project
    would have it's own syntax for allocation class-objects; if you
    standardize it, why not make it an operator with a nice syntax.

    > > Anyhow, I consider new[]/delete[] and raw arrays to be nearly useless.
    > > We have better alternatives and soon get some more: vector<T>,
    > > array<T,N>, unique_ptr<array<T,N>>, for example.

    >
    > Agree. C++ programmers, except those dealing with legacy code or
    > implementing the standard library, can now avoid these irregularities.


    Then, how do you implement a dynamic length array of non-copiable
    objects ?

    --
    Michael
    Michael Doubez, Mar 28, 2011
    #10
  11. Paul

    Öö Tiib Guest

    On Mar 28, 5:27 pm, Michael Doubez <> wrote:
    > On 28 mar, 15:29, Vidar Hasfjord <> wrote:
    > > On Mar 28, 12:25 pm, SG <> wrote:


    > > > Anyhow, I consider new[]/delete[] and raw arrays to be nearly useless..
    > > > We have better alternatives and soon get some more: vector<T>,
    > > > array<T,N>, unique_ptr<array<T,N>>, for example.

    >
    > > Agree. C++ programmers, except those dealing with legacy code or
    > > implementing the standard library, can now avoid these irregularities.

    >
    > Then, how do you implement a dynamic length array of non-copiable
    > objects ?


    Neither copyable nor movable? One may consider either
    boost::scoped_array<T> or std::vector<unique_ptr<T>> depending on
    other constraints.
    Öö Tiib, Mar 28, 2011
    #11
  12. Paul

    A Guest

    > Suppose I have the following code:
    > int (*p)[5] = (int (*)[5])new int[5];
    > How do I delete the allocated memory?


    start using std::vector (or some other container) instead and forget about
    manual memory management. leave it to compiler. you'll have much less memory
    leaks.
    since i started using stl i forgot about how stupid all that manual handling
    of pointers and arrays used to be.

    look how simpler it is:

    // init
    std::vector<int*> p(5);

    // automatically deleted when it loses scope
    A, Mar 28, 2011
    #12
  13. Paul

    Noah Roberts Guest

    On 3/26/2011 10:21 PM, cg_chas wrote:
    > On Sun, 27 Mar 2011 01:19:37 -0400, cg_chas<> wrote:
    >
    >> On Sun, 27 Mar 2011 05:34:51 +0100, "Paul"<> wrote:
    >>
    >>> Hi,
    >>> Suppose I have the following code:
    >>>
    >>> int (*p)[5] = (int (*)[5])new int[5];
    >>>
    >>> How do I delete the allocated memory?
    >>> Is it:
    >>> a) delete[] p;
    >>> b) delete[] *p;
    >>> c) delete[] (int*)p;
    >>>
    >>> ?? Any ideas??

    >>
    >> You have casted the pointer type returned from new into a different pointer, but
    >> regardless, new allocated an array of 5 ints, so you call delete [] on the
    >> pointer that new returned.

    > my correction: should say you have casted the pointer type returned from new
    > into a different pointer "type"


    Both statements are correct. What you actually need to correct is,
    "...so you call delete [] on the pointer that new returned," to, "...so
    you call delete [] on the same pointer type that new returned." Key
    point here is that casting creates new objects.

    --
    http://crazycpp.wordpress.com
    Noah Roberts, Mar 28, 2011
    #13
  14. Paul

    Paul Guest

    "Vidar Hasfjord" <> wrote in message
    news:80d512c9-799d-445d-bd99->...
    >On Mar 27, 5:34 am, "Paul" <> wrote:
    >> [Suppose I have the following code:
    >>
    >> int (*p)[5] = (int (*)[5])new int[5];
    >>
    >> How do I delete the allocated memory?


    >As your question has been answered elsewhere, I'll just add an
    >interesting aside from a language design perspective. If C++ had a
    >more regular design the type of the "new int [5]" expression would not
    >degenerate to "int*". A regular design would render the array
    >overloads of new and delete superfluous, and make your cast here
    >unnecessary. Consider the irregularity of:


    I don't think my question has bene answered, what I was asking was the
    difference between each delete invocation, it seems that each is identical
    but I get warning for delete *p, see code:

    class Base{
    public:
    Base() {std::cout<<"Constructing base\n";}
    ~Base(){std::cout<<"Destructing base\n";}
    };

    int main() {
    Base (*pA)[4] = (Base (*)[4])new Base[4];
    Base* pB = new Base[3];

    std::cout<<"\nDeleting pA:\n";
    delete[] pA;
    //delete[] *pA;
    std::cout<<"\nDeleting pB:\n";
    delete[] pB;


    If you run the above code you see that each invocation of delete[] produces
    the desired effect, even if you use *pA instead of pA. This however gives a
    warning but I think the array is converted to a pointer. I did my tests on a
    windows platform but it may not be the same on other platforms.
    This suggests to me that the pointer-type is not rellevant, on my platform
    at least, when calling delete[].

    > typedef struct {int a, b, c, d, e;} Struct; // aggregate type
    > typedef int Array [5]; // aggregate type
    > Struct* ps = new Struct; // Ok!
    > Array* pa = new Array; // Error! Should be "int* pa".
    > delete ps; // Ok!
    > delete pa; // Error! Should be "delete [] pa".


    >If instead C++ was regular and this was correct code, the type of the
    >pointer would carry the size information and allow the regular delete
    >operator to release the correct amount of memory. These irregularities
    >are avoided by std::array:


    Yeah but it's never going to be a regular language, that is not the nature
    of comp programming. All you can do is wrap it up in some class and make it
    apper like regular syntax. I'm no big fan of unnecessary wrapping.

    > typedef std::array <int, 5> Array; // aggregate type
    > Array* pa = new Array; // Ok!
    > delete pa; // Ok!


    Yes but look at all the extra code you need to introduce behind the scenes
    to get these semantics. I don't see any advantage in using an STL class over
    a pointer in many cases, there are some cases where they are perfect and
    really good , but not always.

    >Dereferencing the pointer, (*pa), gives you a reference (lvalue) to
    >the array as a whole, and an indexing operator is implemented for the
    >array class itself (not via degeneration into pointer arithmetic).


    Thats simple to achieve without the introduction of a STL class, for
    example:

    int (*pA)[6] = (int (*)[6])new int[6];
    int (&rA)[6] = *pA;

    The only advantage I see for using STL vectors is that they are expandable.
    If you need a quick fix generic expandable array I agree they are the
    solution. But for a simple fixed size array I wouldn't bother with an STL
    class.

    >The new std::array circumvents the numerous irregularities between
    >pointers and arrays that causes so much confusion. I.e. you can copy
    >arrays, pass and return arrays by value to and from functions, and the
    >array will never implicitly convert to a pointer to the first element.
    >Hence I recommend its use instead of C-style arrays.


    I've never really used it TBH, my compiler setup doesn't seem to have that
    library.
    I don't really see the need for it in most cases, I'm quite happy with
    normal C++ arrays, I'm just a bit rusty on C++ so I was trying to confirm
    the behaviour of delete[] with the given cases.
    TY for your post
    Paul.
    Paul, Mar 28, 2011
    #14
  15. On Mar 28, 6:37 pm, "Paul" <> wrote:
    > This suggests to me that the pointer-type is not rellevant, on my platform
    > at least, when calling delete[].


    While it may not make a difference in this particular example, in
    general it is very much relevant. The correct type is needed for
    delete to call the correct destructor. Also note that both "delete"
    and "delete[]" can be overloaded globally and per class, in which case
    the correct type is needed to select the correct overload.

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Mar 28, 2011
    #15
  16. Paul

    Paul Guest

    "Kai-Uwe Bux" <> wrote in message
    news:imqo3l$l45$...
    > Paul wrote:
    >
    >>
    >>>"Öö Tiib" <> wrote in message
    >>>news:...
    >>>On Mar 27, 7:34 am, "Paul" <> wrote:
    >>>> Hi,
    >>>> Suppose I have the following code:
    >>>>
    >>>> int (*p)[5] = (int (*)[5])new int[5];
    >>>>
    >>>> How do I delete the allocated memory?
    >>>> Is it:
    >>>> a) delete[] p;
    >>>> b) delete[] *p;
    >>>> c) delete[] (int*)p;
    >>>>
    >>>> ?? Any ideas??
    >>>
    >>>I think that c) but why you reinterpret_cast at first place?
    >>>

    >> To convert the dynamic array into an array object type, that would decay
    >> into a pointer that carried size information, for example:
    >>
    >> template<typename T, int S, typename U= T (&)>
    >> class R{
    >> public:
    >> R():pp((int (*))new int[S+1]), r(*(pp+1)){r[-1]=S;}
    >> U getArray(){return r;}
    >> void delete_it(){ delete[] (int*)pp; }
    >> private:
    >> int (*pp);
    >> T (&r);
    >> };
    >>
    >> template<typename T>
    >> void foo(T r){
    >> std::cout<<"size of array:\t" << r[-1];
    >> std::cout<< "\ntype of array:\t" << typeid(T).name();
    >> }
    >>
    >> int main() {
    >> R<int, 7> r;
    >> int (&r1)[7] = r.getArray();
    >> foo(r.getArray());
    >> std::cout<<"\ntype of r1:\t"<< typeid(r1).name();
    >>
    >> r.delete_it();
    >> }

    > [...]
    >
    > The above seems to be rather roundabout. Also, the templates indicate a
    > generality that is not really there: if you try to instantiate R<long,7>
    > the
    > code will not compile. Furthermore, I do not understand why you would want
    > to store size information within the array when it is available through
    > the
    > type system: after all, the array size is passed as a template parameter
    > whence it must be a compile time constant. Finally, the casting could
    > invoke
    > undefined behavior as soon as you access array elements (any use other
    > than
    > casting back is undefined, I think).
    >
    > For comparison look at the free functions new_it<> and delete_it<>. To me,
    > it seems, that they do the same as the above class R<> except that the
    > size
    > is not required to be a compile time constant. (Also, now the templates
    > work
    > for types T!=int.)
    >
    > #include <iostream>
    > #include <ostream>
    > #include <typeinfo>
    >
    >
    > template<typename T, int S, typename U= T (&)>
    > class R{
    > public:
    > R():pp((int (*))new int[S+1]), r(*(pp+1)){r[-1]=S;}
    > U getArray(){return r;}
    > void delete_it(){ delete[] (int*)pp; }
    > private:
    > int (*pp);
    > T (&r);
    > };
    >
    > template < typename IntegerType >
    > IntegerType * new_it ( int size ) {
    > IntegerType * ptr = new IntegerType [size+1];
    > ptr[0] = size;
    > return ( ptr+1 );
    > }
    >
    > template < typename IntegerType >
    > void delete_it ( IntegerType * ptr ) {
    > delete ( ptr-1 );
    > }
    >
    > template<typename T>
    > void foo(T r){
    > std::cout<<"size of array:\t" << r[-1];
    > std::cout<< "\ntype of array:\t" << typeid(T).name();
    > }
    >
    > int main() {
    > {
    > R<int, 7> r; // try R<long,7> here.
    > int (&r1)[7] = r.getArray();
    > foo(r.getArray());
    > std::cout<<"\ntype of r1:\t"<< typeid(r1).name();
    > r.delete_it();
    > }
    > {
    > std::cout << "\n";
    > int * ptr = new_it<int>(7); // try long * ptr = new_it<long>(7) here;
    > foo(ptr);
    > delete_it( ptr );
    > std::cout << "\n";
    > }
    > }
    >
    >

    Yes there are lots of ways to do it , the code was just a example..
    TY
    Paul.
    Paul, Mar 28, 2011
    #16
  17. Paul

    Paul Guest

    "Vidar Hasfjord" <> wrote in message
    news:35e223bd-251f-4697-aa66->...
    >On Mar 28, 6:37 pm, "Paul" <> wrote:
    >> This suggests to me that the pointer-type is not rellevant, on my
    >> platform
    >> at least, when calling delete[].


    >While it may not make a difference in this particular example, in
    >general it is very much relevant. The correct type is needed for
    >delete to call the correct destructor. Also note that both "delete"
    >and "delete[]" can be overloaded globally and per class, in which case
    >the correct type is needed to select the correct overload.


    I'm not talking about pointer-types , in general. I'm talking about pointer
    to arrays and pointer to array-object types as in:
    int* or int(*)[size];
    Base* or Base (*)[size]
    etc etc.

    If I call delete[] on int*, it's no different to int (*)[size]? Or is it?
    How does the compiler know how many destructors to call?
    And what if call delete[] *(int (*)[size])? Is it implicitly converted to
    int*?
    Paul, Mar 28, 2011
    #17
  18. On Mar 28, 3:27 pm, Michael Doubez <> wrote:
    > This seems contradictory, the irregularity of array with runtime size
    > is AFAIS intended for providing a regular type expression syntax to
    > use with new operator.


    Granted, you can say a similarity of syntax is regularity, but the
    semantic irregularity it causes is high, and it was the semantic
    irregularities I alluded to here. I view it as undesirable that the
    type-id syntax has been reused to specify a run-time parameter.

    > > template <class T> T* construct (size_t n = 1); // replaces new
    > > template <class T> void destruct (T*); // replaces delete

    >
    > And how do you handle constructor parameters for non-array
    > initialisation ?
    > For a workable solution, you would need perfect forwarding which isn't
    > yet standard.


    Sorry, these were meant to replace just "new[]" and "delete[]",
    leaving "new" and "delete" as before, but with regular semantics.
    Perfect forwarding would make it feasable to also replace "new" and
    "delete", although the language would still need placement-new, or
    something similar, to construct objects in allocated memory.

    > Moreover, this means that unless you standardise it, every project
    > would have it's own syntax for allocation class-objects; if you
    > standardize it, why not make it an operator with a nice syntax.


    I'm just hypothesising about a regular subset of C++ here, but yes,
    you may assume it would have the necessary features in the language
    and support in the library. But I don't see how an operator can be
    much nicer than template syntax. This is the road we're on, anyway (C+
    +0x):

    auto pa = make_shared <A> (...); // Create A, return shared_ptr.

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Mar 28, 2011
    #18
  19. On Mar 28, 9:26 pm, "Paul" <> wrote:
    > If I call delete[] on int*, it's no different to int (*)[size]? Or is it?


    You may have to consult the C++ standard to see if it gives any
    guarantees. Despite your casts, "int*" is what "new" returned, so that
    seems the only sure thing. Maybe allowing "int (*)[size]" is a
    concession from the compiler for having decayed the type in the first
    place? :)

    > How does the compiler know how many destructors to call?


    See:
    http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.14

    > delete[] *(int (*)[size])? Is it implicitly converted to int*?


    Yes, and Visual C++ 2010 also produces a warning in this case (warning
    C4154: deletion of an array expression; conversion to pointer
    supplied).

    Regards,
    Vidar Hasfjord
    Vidar Hasfjord, Mar 29, 2011
    #19
  20. Paul

    Paul Guest

    "Vidar Hasfjord" <> wrote in message
    news:...
    > On Mar 28, 9:26 pm, "Paul" <> wrote:
    >> If I call delete[] on int*, it's no different to int (*)[size]? Or is it?

    >
    > You may have to consult the C++ standard to see if it gives any
    > guarantees. Despite your casts, "int*" is what "new" returned, so that
    > seems the only sure thing. Maybe allowing "int (*)[size]" is a
    > concession from the compiler for having decayed the type in the first
    > place? :)
    >
    >> How does the compiler know how many destructors to call?

    >
    > See:
    > http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.14


    Yes I already knew about these techniques.
    What my concern was that with delete [] called on int (*)[size] type
    pointer...
    C++ would call the destructor for the 1st element, then move
    size*sizeof(int), that is sizeof( *(int (*)[size]) ) to look for the second
    element. As oppose to moving only sizeof(int) per element, in the case of
    delete[] int*
    .. Therefore I would be freeing more memory than I allocated, but this
    doesn't seen to happen

    >
    >> delete[] *(int (*)[size])? Is it implicitly converted to int*?

    >
    > Yes, and Visual C++ 2010 also produces a warning in this case (warning
    > C4154: deletion of an array expression; conversion to pointer
    > supplied).
    >

    Ah nice that confirms that , for VC++ at least.
    Ty again for your post.
    Paul, Mar 29, 2011
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sandeep Grover

    delete on delete !

    Sandeep Grover, Jul 12, 2003, in forum: C++
    Replies:
    19
    Views:
    609
    Chris \( Val \)
    Jul 22, 2003
  2. HeroOfSpielburg
    Replies:
    1
    Views:
    379
    Alf P. Steinbach
    Aug 6, 2003
  3. 0to60
    Replies:
    4
    Views:
    307
    Jerry Coffin
    Dec 19, 2003
  4. Mathieu Malaterre

    delete NULL, what about delete[] NULL

    Mathieu Malaterre, Aug 17, 2004, in forum: C++
    Replies:
    2
    Views:
    3,810
    Mathieu Malaterre
    Aug 17, 2004
  5. Jef Driesen
    Replies:
    1
    Views:
    492
    Gernot Frisch
    Jan 19, 2005
Loading...

Share This Page