Lets put it another way

Discussion in 'C++' started by Paul, May 24, 2011.

  1. Paul

    Paul Guest

    Ok in connection to my previous post, lets remove the null pointer issue and
    consider this:

    #include <iostream>

    typedef int (*pparr)[3];

    int main(){
    pparr p1 = (pparr)new int[3];
    pparr p2= p1;
    delete[] p1;
    std::cout<< *p2<<std::endl;
    std::cout<< typeid(*p2).name();
    }


    In the last 2 lines does an array type object exist, even though there is no
    array object?

    If not what is the object that stores the address and is interpreted as an
    array type by the typeid expression?
     
    Paul, May 24, 2011
    #1
    1. Advertising

  2. Paul

    Ian Collins Guest

    On 05/24/11 01:14 PM, Paul wrote:
    > Ok in connection to my previous post, lets remove the null pointer issue and
    > consider this:
    >
    > #include<iostream>
    >
    > typedef int (*pparr)[3];
    >
    > int main(){
    > pparr p1 = (pparr)new int[3];
    > pparr p2= p1;
    > delete[] p1;
    > std::cout<< *p2<<std::endl;


    UB yet again.

    > std::cout<< typeid(*p2).name();
    > }
    >
    >
    > In the last 2 lines does an array type object exist, even though there is no
    > array object?


    No.

    > If not what is the object that stores the address and is interpreted as an
    > array type by the typeid expression?


    The typeid and sizeof operators do not evaluate their expression (unless
    in case of typeid the type is polymorphic). So no object is required.

    --
    Ian Collins
     
    Ian Collins, May 24, 2011
    #2
    1. Advertising

  3. On May 23, 6:33 pm, Ian Collins <> wrote:
    > On 05/24/11 01:14 PM, Paul wrote:
    >
    > > Ok in connection to my previous post, lets remove the null pointer issue and
    > > consider this:

    >
    > > #include<iostream>

    >
    > > typedef int (*pparr)[3];

    >
    > > int main(){
    > >   pparr p1 = (pparr)new int[3];
    > >   pparr p2= p1;
    > >   delete[] p1;
    > >   std::cout<<  *p2<<std::endl;

    >
    > UB yet again.


    Actually, he has UB even earlier. He has UB at the delete[]. The type
    of the expression "new int[3]" is "int*". The type of the expression
    passed to delete[] to free that object must be the same type, "int*".
    It's not, and thus UB.
     
    Joshua Maurice, May 24, 2011
    #3
  4. Paul

    Paul Guest

    "Ian Collins" <> wrote in message
    news:...
    > On 05/24/11 01:14 PM, Paul wrote:
    >> Ok in connection to my previous post, lets remove the null pointer issue
    >> and
    >> consider this:
    >>
    >> #include<iostream>
    >>
    >> typedef int (*pparr)[3];
    >>
    >> int main(){
    >> pparr p1 = (pparr)new int[3];
    >> pparr p2= p1;
    >> delete[] p1;
    >> std::cout<< *p2<<std::endl;

    >
    > UB yet again.
    >
    >> std::cout<< typeid(*p2).name();
    >> }
    >>
    >>
    >> In the last 2 lines does an array type object exist, even though there is
    >> no
    >> array object?

    >
    > No.
    >
    >> If not what is the object that stores the address and is interpreted as
    >> an
    >> array type by the typeid expression?

    >
    > The typeid and sizeof operators do not evaluate their expression (unless
    > in case of typeid the type is polymorphic). So no object is required.
    >

    You do not seem to understand the question.
    I said ..if not what is the object that stores the address?
    So what is this object? Do you know?
     
    Paul, May 24, 2011
    #4
  5. Paul

    Paul Guest

    "Joshua Maurice" <> wrote in message
    news:...
    On May 23, 6:33 pm, Ian Collins <> wrote:
    > On 05/24/11 01:14 PM, Paul wrote:
    >
    > > Ok in connection to my previous post, lets remove the null pointer issue
    > > and
    > > consider this:

    >
    > > #include<iostream>

    >
    > > typedef int (*pparr)[3];

    >
    > > int main(){
    > > pparr p1 = (pparr)new int[3];
    > > pparr p2= p1;
    > > delete[] p1;
    > > std::cout<< *p2<<std::endl;

    >
    > UB yet again.


    --Actually, he has UB even earlier. He has UB at the delete[]. The type
    --of the expression "new int[3]" is "int*". The type of the expression
    --passed to delete[] to free that object must be the same type, "int*".
    --It's not, and thus UB.

    I raised this question about delete or delete[] on 28/03/2011 and you didn't
    know the answer then.
    The objects that need to be deleted are integer objects. and they get
    deleted in this case.
    If you think it is necessary to cast to int* prior to calling delete then
    assume that and then can you answer the question about the object that
    contains the memory address, or do you not know?
     
    Paul, May 24, 2011
    #5
  6. On May 24, 2:42 am, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    >
    > news:...
    > On May 23, 6:33 pm, Ian Collins <> wrote:
    >
    > > On 05/24/11 01:14 PM, Paul wrote:

    >
    > > > Ok in connection to my previous post, lets remove the null pointer issue
    > > > and
    > > > consider this:

    >
    > > > #include<iostream>

    >
    > > > typedef int (*pparr)[3];

    >
    > > > int main(){
    > > > pparr p1 = (pparr)new int[3];
    > > > pparr p2= p1;
    > > > delete[] p1;
    > > > std::cout<< *p2<<std::endl;

    >
    > > UB yet again.

    >
    > --Actually, he has UB even earlier. He has UB at the delete[]. The type
    > --of the expression "new int[3]" is "int*". The type of the expression
    > --passed to delete[] to free that object must be the same type, "int*".
    > --It's not, and thus UB.
    >
    > I raised this question about delete or delete[] on 28/03/2011 and you didn't
    > know the answer then.


    I'm pretty sure I knew, and I suspect that you're willfully lying.

    > The objects that need to be deleted are integer objects. and they get
    > deleted in this case.


    No. An array object is the thing that was allocated, and it is an
    array object that needs to be passed to delete[].

    > If you think it is necessary to cast to int* prior to calling delete then
    > assume that


    It's not what I think. It's what the standard says.

    > and then can you answer the question about the object that
    > contains the memory address, or do you not know?


    Your original question in the OP post about "array type objects" vs
    "array objects" makes no sense because you invented the terms, and no
    one else knows what they mean.

    #include<iostream>
    typedef int (*pparr)[3];
    int main(){
    pparr p1 = (pparr)new int[3];
    pparr p2= p1;
    delete[] p1;
    std::cout<< *p2<<std::endl;
    }

    This program
    1- dynamically allocates an array object, specifically "int [3]",
    2- does some funky incorrect casting invoking platform specific
    behavior (we're not guaranteed that a "int (*)[3]" pointer can round-
    trip store a "int *" pointer),
    3- calls delete[] on a pointer of the wrong type and thus invokes UB,
    4- and finally, the program again invokes UB by attempting to read the
    result of a null pointer dereference.
     
    Joshua Maurice, May 24, 2011
    #6
  7. On May 24, 3:00 am, Joshua Maurice <> wrote:
    > 4- and finally, the program again invokes UB by attempting to read the
    > result of a null pointer dereference.


    Err, sorry, not null pointer dereference. My apologies. It's an
    indeterminate value. This is clearer in the C standard where they
    cleared this up recently AFAIK. As soon as a pointer to a dynamically
    allocated piece of memory has been passed to a deallocation function,
    all copies of that pointer value, and moreover all pointer values in
    the entire program that point into that region of memory, become
    indeterminant. Any read of an indeterminant value is UB.
     
    Joshua Maurice, May 24, 2011
    #7
  8. Paul

    Ian Collins Guest

    On 05/24/11 09:20 PM, Paul wrote:
    >
    > "Ian Collins"<> wrote in message
    > news:...
    >> On 05/24/11 01:14 PM, Paul wrote:
    >>> Ok in connection to my previous post, lets remove the null pointer issue
    >>> and
    >>> consider this:
    >>>
    >>> #include<iostream>
    >>>
    >>> typedef int (*pparr)[3];
    >>>
    >>> int main(){
    >>> pparr p1 = (pparr)new int[3];
    >>> pparr p2= p1;
    >>> delete[] p1;
    >>> std::cout<< *p2<<std::endl;

    >>
    >> UB yet again.
    >>
    >>> std::cout<< typeid(*p2).name();
    >>> }
    >>>
    >>>
    >>> In the last 2 lines does an array type object exist, even though there is
    >>> no
    >>> array object?

    >>
    >> No.
    >>
    >>> If not what is the object that stores the address and is interpreted as
    >>> an
    >>> array type by the typeid expression?

    >>
    >> The typeid and sizeof operators do not evaluate their expression (unless
    >> in case of typeid the type is polymorphic). So no object is required.
    >>

    > You do not seem to understand the question.


    You do not appear to understand the answer.

    > I said ..if not what is the object that stores the address?
    > So what is this object? Do you know?


    There isn't an object. The compiler knows the type of *p2. You may as
    well have written

    #include <iostream>
    #include <typeinfo>

    typedef int (*pparr)[3];

    int main(){
    pparr p2;
    std::cout << typeid(*p2).name() << std::endl;
    }


    --
    Ian Collins
     
    Ian Collins, May 24, 2011
    #8
  9. Paul

    Paul Guest

    "Ian Collins" <> wrote in message
    news:...
    > On 05/24/11 09:20 PM, Paul wrote:
    >>
    >> "Ian Collins"<> wrote in message
    >> news:...
    >>> On 05/24/11 01:14 PM, Paul wrote:
    >>>> Ok in connection to my previous post, lets remove the null pointer
    >>>> issue
    >>>> and
    >>>> consider this:
    >>>>
    >>>> #include<iostream>
    >>>>
    >>>> typedef int (*pparr)[3];
    >>>>
    >>>> int main(){
    >>>> pparr p1 = (pparr)new int[3];
    >>>> pparr p2= p1;
    >>>> delete[] p1;
    >>>> std::cout<< *p2<<std::endl;
    >>>
    >>> UB yet again.
    >>>
    >>>> std::cout<< typeid(*p2).name();
    >>>> }
    >>>>
    >>>>
    >>>> In the last 2 lines does an array type object exist, even though there
    >>>> is
    >>>> no
    >>>> array object?
    >>>
    >>> No.
    >>>
    >>>> If not what is the object that stores the address and is interpreted as
    >>>> an
    >>>> array type by the typeid expression?
    >>>
    >>> The typeid and sizeof operators do not evaluate their expression (unless
    >>> in case of typeid the type is polymorphic). So no object is required.
    >>>

    >> You do not seem to understand the question.

    >
    > You do not appear to understand the answer.
    >
    >> I said ..if not what is the object that stores the address?
    >> So what is this object? Do you know?

    >
    > There isn't an object. The compiler knows the type of *p2. You may as
    > well have written
    >
    > #include <iostream>
    > #include <typeinfo>
    >
    > typedef int (*pparr)[3];
    >
    > int main(){
    > pparr p2;
    > std::cout << typeid(*p2).name() << std::endl;
    > }
    >
    >

    You are not addressing the what stores the memory address.
    A memory address value is stored so there must be an object to store this
    value, you say there is no object so what is it that stores this value?
     
    Paul, May 24, 2011
    #9
  10. Paul

    Paul Guest

    "Joshua Maurice" <> wrote in message
    news:...
    On May 24, 2:42 am, "Paul" <> wrote:
    > > On 05/24/11 01:14 PM, Paul wrote:

    >
    > > > Ok in connection to my previous post, lets remove the null pointer
    > > > issue
    > > > and
    > > > consider this:

    >
    > > > #include<iostream>

    >
    > > > typedef int (*pparr)[3];

    >
    > > > int main(){
    > > > pparr p1 = (pparr)new int[3];
    > > > pparr p2= p1;
    > > > delete[] p1;
    > > > std::cout<< *p2<<std::endl;

    >
    > > UB yet again.

    >
    > --Actually, he has UB even earlier. He has UB at the delete[]. The type
    > --of the expression "new int[3]" is "int*". The type of the expression
    > --passed to delete[] to free that object must be the same type, "int*".
    > --It's not, and thus UB.
    >
    > I raised this question about delete or delete[] on 28/03/2011 and you
    > didn't
    > know the answer then.


    --I'm pretty sure I knew, and I suspect that you're willfully lying.

    No I'm not lying. In response to my question about how to delete such an
    object you wrote:

    "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?"

    Ref: Posting on "delete or delete[]" on 28/3/2011



    > The objects that need to be deleted are integer objects. and they get
    > deleted in this case.


    --No. An array object is the thing that was allocated, and it is an
    --array object that needs to be passed to delete[].

    No three integer objects were allocated and three integers must be
    deallocated.
    It is not one object that is allocated is it three, as this code shows:

    #include <iostream>

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

    typedef Foo (*arr_ptr)[3];

    int main(){
    arr_ptr foop = (arr_ptr)new Foo[3];
    delete[] (Foo*)foop; /*cast back to keep you happy :)*/
    }


    > If you think it is necessary to cast to int* prior to calling delete then
    > assume that


    --It's not what I think. It's what the standard says.

    The deletion of the dynamically allocated array was not really relevant but
    if you must argue about this then cast it back as I did in my code above.

    > and then can you answer the question about the object that
    > contains the memory address, or do you not know?


    --Your original question in the OP post about "array type objects" vs
    --"array objects" makes no sense because you invented the terms, and no
    --one else knows what they mean.

    My question is about the object that stores the memory address we get when
    we dereference p2.


    --#include<iostream>
    --typedef int (*pparr)[3];
    --int main(){
    -- pparr p1 = (pparr)new int[3];
    -- pparr p2= p1;
    -- delete[] p1;
    -- std::cout<< *p2<<std::endl;
    --}

    --This program
    --1- dynamically allocates an array object, specifically "int [3]",

    I don't see it as allocating one single object , I see it as allocating and
    array of 3 int objects.


    --2- does some funky incorrect casting invoking platform specific
    --behavior (we're not guaranteed that a "int (*)[3]" pointer can round-
    --trip store a "int *" pointer),

    In what way is this pointer casting incorrect?
    I would be very surprised if this cast was incorrect as it is a usefull way
    of converting a dynamic array into a reference type, for example:

    class Foo{
    public:
    Foo(){std::cout<<"Constructing Foo\n";}
    ~Foo(){std::cout<<"Destructing Foo\n";}
    int x;
    };

    void Bar( Foo (&arg)[3]){
    std::cout<<"In Bar\n";
    arg[0].x= 1;
    arg[1].x= 2;
    arg[2].x= 3;
    }

    typedef Foo (*arr_ptr)[3];

    int main(){
    arr_ptr foop = (arr_ptr)new Foo[3];
    Bar(*foop);
    std::cout<< (*foop)[2].x;
    }



    --3- calls delete[] on a pointer of the wrong type and thus invokes UB,

    That is easily corrected by casting back , this is not a point important to
    the question.

    --4- and finally, the program again invokes UB by attempting to read the
    --result of a null pointer dereference.

    There is no null pointers here.
     
    Paul, May 24, 2011
    #10
  11. Paul

    Paul Guest

    "Joshua Maurice" <> wrote in message
    news:...
    On May 24, 3:00 am, Joshua Maurice <> wrote:
    > 4- and finally, the program again invokes UB by attempting to read the
    > result of a null pointer dereference.


    --Err, sorry, not null pointer dereference. My apologies. It's an
    --indeterminate value. This is clearer in the C standard where they
    --cleared this up recently AFAIK. As soon as a pointer to a dynamically
    --allocated piece of memory has been passed to a deallocation function,
    --all copies of that pointer value, and moreover all pointer values in
    --the entire program that point into that region of memory, become
    --indeterminant. Any read of an indeterminant value is UB.


    *p2 does not attempt to access the deallocated memory.
    *p2 yields a memory address, it accesses some object that seems to be a
    pointer in most situations, but when passed to typeid or sizeof it does not
    behave like a pointer.
    This AFAICT from reading online seems to be the typical behaviour of a C++
    array type object, therefore it seems that the pointer points to an array
    type object which is created by the creation of the pointer itself and not
    by the allocation.

    For example consider this simple example:
    int* p = new int[16];

    In this dynamic array there is no array type object. It is a simple int*
    that points to a block of memory.
    sizeof and typeid do not work here because there is no array object.
    Now consider this:

    int (*p)[3] = (int (*)[3])new int[3];
    Now we have an arraytype object because we can access typeinfo and sizeof.

    The allocation of memory alone does not create an array type object, it is
    the declaration of an object using square brackets that creates the array
    type object.
     
    Paul, May 24, 2011
    #11
  12. Paul

    Ian Collins Guest

    On 05/25/11 12:58 AM, Paul wrote:
    >
    > "Ian Collins"<> wrote in message
    > news:...
    >> On 05/24/11 09:20 PM, Paul wrote:
    >>>
    >>> "Ian Collins"<> wrote in message
    >>> news:...
    >>>> On 05/24/11 01:14 PM, Paul wrote:
    >>>>> Ok in connection to my previous post, lets remove the null pointer
    >>>>> issue
    >>>>> and
    >>>>> consider this:
    >>>>>
    >>>>> #include<iostream>
    >>>>>
    >>>>> typedef int (*pparr)[3];
    >>>>>
    >>>>> int main(){
    >>>>> pparr p1 = (pparr)new int[3];
    >>>>> pparr p2= p1;
    >>>>> delete[] p1;
    >>>>> std::cout<< *p2<<std::endl;
    >>>>
    >>>> UB yet again.
    >>>>
    >>>>> std::cout<< typeid(*p2).name();
    >>>>> }
    >>>>>
    >>>>>
    >>>>> In the last 2 lines does an array type object exist, even though there
    >>>>> is
    >>>>> no
    >>>>> array object?
    >>>>
    >>>> No.
    >>>>
    >>>>> If not what is the object that stores the address and is interpreted as
    >>>>> an
    >>>>> array type by the typeid expression?
    >>>>
    >>>> The typeid and sizeof operators do not evaluate their expression (unless
    >>>> in case of typeid the type is polymorphic). So no object is required.
    >>>>
    >>> You do not seem to understand the question.

    >>
    >> You do not appear to understand the answer.
    >>
    >>> I said ..if not what is the object that stores the address?
    >>> So what is this object? Do you know?

    >>
    >> There isn't an object. The compiler knows the type of *p2. You may as
    >> well have written
    >>
    >> #include<iostream>
    >> #include<typeinfo>
    >>
    >> typedef int (*pparr)[3];
    >>
    >> int main(){
    >> pparr p2;
    >> std::cout<< typeid(*p2).name()<< std::endl;
    >> }
    >>
    >>

    > You are not addressing the what stores the memory address.


    Because there isn't an address to store. The typeid operator (like
    sizeof) works with types, not values. In a simple case such as this the
    operand is not evaluated. Until you understand this you will be stuck
    in limbo.

    I could have simplified my simplification further by writing

    std::cout << typeid(int[3]).name() << std::endl;

    See? No memory address just a type.

    > A memory address value is stored so there must be an object to store this
    > value, you say there is no object so what is it that stores this value?


    There isn't an address. Where's the address in typeid(int).name()? Or
    sizeof(int)?

    --
    Ian Collins
     
    Ian Collins, May 24, 2011
    #12
  13. Paul

    Paul Guest

    "Ian Collins" <> wrote in message
    news:...
    > On 05/25/11 12:58 AM, Paul wrote:
    >>
    >>>>>> Ok in connection to my previous post, lets remove the null pointer
    >>>>>> issue
    >>>>>> and
    >>>>>> consider this:
    >>>>>>
    >>>>>> #include<iostream>
    >>>>>>
    >>>>>> typedef int (*pparr)[3];
    >>>>>>
    >>>>>> int main(){
    >>>>>> pparr p1 = (pparr)new int[3];
    >>>>>> pparr p2= p1;
    >>>>>> delete[] p1;
    >>>>>> std::cout<< *p2<<std::endl;
    >>>>>
    >>>>> UB yet again.
    >>>>>
    >>>>>> std::cout<< typeid(*p2).name();
    >>>>>> }
    >>>>>>
    >>>>>>
    >>>>>> In the last 2 lines does an array type object exist, even though
    >>>>>> there
    >>>>>> is
    >>>>>> no
    >>>>>> array object?
    >>>>>
    >>>>> No.
    >>>>>
    >>>>>> If not what is the object that stores the address and is interpreted
    >>>>>> as
    >>>>>> an
    >>>>>> array type by the typeid expression?
    >>>>>
    >>>>> The typeid and sizeof operators do not evaluate their expression
    >>>>> (unless
    >>>>> in case of typeid the type is polymorphic). So no object is required.
    >>>>>
    >>>> You do not seem to understand the question.
    >>>
    >>> You do not appear to understand the answer.
    >>>
    >>>> I said ..if not what is the object that stores the address?
    >>>> So what is this object? Do you know?
    >>>
    >>> There isn't an object. The compiler knows the type of *p2. You may as
    >>> well have written
    >>>
    >>> #include<iostream>
    >>> #include<typeinfo>
    >>>
    >>> typedef int (*pparr)[3];
    >>>
    >>> int main(){
    >>> pparr p2;
    >>> std::cout<< typeid(*p2).name()<< std::endl;
    >>> }
    >>>
    >>>

    >> You are not addressing the what stores the memory address.

    >
    > Because there isn't an address to store. The typeid operator (like
    > sizeof) works with types, not values. In a simple case such as this the
    > operand is not evaluated. Until you understand this you will be stuck in
    > limbo.
    >
    > I could have simplified my simplification further by writing
    >
    > std::cout << typeid(int[3]).name() << std::endl;
    >
    > See? No memory address just a type.
    >


    There is an address stored.

    Look at the code :

    int main(){
    int (*pp)[3] = (int (*)[3])new int[3];
    std::cout<<*pp;
    }
    If this does not output an address what the hell is it?


    >> A memory address value is stored so there must be an object to store this
    >> value, you say there is no object so what is it that stores this value?

    >
    > There isn't an address. Where's the address in typeid(int).name()? Or
    > sizeof(int)?
    >

    The address is shown in my code above.
    Have you lost your brain today?
     
    Paul, May 24, 2011
    #13
  14. On May 24, 6:54 am, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    >
    > news:...
    > On May 24, 3:00 am, Joshua Maurice <> wrote:
    >
    > > 4- and finally, the program again invokes UB by attempting to read the
    > > result of a null pointer dereference.

    >
    > --Err, sorry, not null pointer dereference. My apologies. It's an
    > --indeterminate value. This is clearer in the C standard where they
    > --cleared this up recently AFAIK. As soon as a pointer to a dynamically
    > --allocated piece of memory has been passed to a deallocation function,
    > --all copies of that pointer value, and moreover all pointer values in
    > --the entire program that point into that region of memory, become
    > --indeterminant. Any read of an indeterminant value is UB.
    >
    > *p2 does not attempt to access the deallocated memory.


    Doesn't matter. It's UB. Attempting to read the pointer, not the
    deallocated memory, is UB. At least it is according to the C spec, and
    I expect that the C++ standard will follow suit if it hasn't already.

    > For example consider this simple example:
    > int* p = new int[16];
    >
    > In this dynamic array there is no array type object. It is a simple int*
    > that points to a block of memory.
    > sizeof and typeid do not work here because there is no array object.
    > Now consider this:
    >
    > int (*p)[3] = (int (*)[3])new int[3];
    > Now we have an arraytype object because we can access typeinfo and sizeof..
    >
    > The allocation of memory alone does not create an array type object, it is
    > the declaration of an object using square brackets that creates the array
    > type object.


    And I still don't know what you mean by array type object vs array
    object. Until you explain that technical distinction to me, you're
    literally just spouting effective nonsense, as you just invented those
    terms and no one else knows what you're saying.
     
    Joshua Maurice, May 24, 2011
    #14
  15. On May 24, 6:32 am, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    > --3- calls delete[] on a pointer of the wrong type and thus invokes UB,
    >
    > That is easily corrected by casting back , this is not a point important to
    > the question.


    Any dereference of that pointer, basically, is UB. There's no reason
    to do the cast in the first place.
     
    Joshua Maurice, May 24, 2011
    #15
  16. Paul

    Paul Guest

    "Joshua Maurice" <> wrote in message
    news:...
    On May 24, 6:54 am, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    > > 4- and finally, the program again invokes UB by attempting to read the
    > > result of a null pointer dereference.

    >
    > --Err, sorry, not null pointer dereference. My apologies. It's an
    > --indeterminate value. This is clearer in the C standard where they
    > --cleared this up recently AFAIK. As soon as a pointer to a dynamically
    > --allocated piece of memory has been passed to a deallocation function,
    > --all copies of that pointer value, and moreover all pointer values in
    > --the entire program that point into that region of memory, become
    > --indeterminant. Any read of an indeterminant value is UB.
    >
    > *p2 does not attempt to access the deallocated memory.


    --Doesn't matter. It's UB. Attempting to read the pointer, not the
    --deallocated memory, is UB. At least it is according to the C spec, and
    --I expect that the C++ standard will follow suit if it hasn't already

    This pointer obviously points to something that has a value that is
    displayed on the screen as a memory address. It certainly doesn't point to
    the integer objects that were allocated by new, so what does it point to?
    How can you say it is UB if you do not first establish what it is pointing
    to?

    > For example consider this simple example:
    > int* p = new int[16];
    >
    > In this dynamic array there is no array type object. It is a simple int*
    > that points to a block of memory.
    > sizeof and typeid do not work here because there is no array object.
    > Now consider this:
    >
    > int (*p)[3] = (int (*)[3])new int[3];
    > Now we have an arraytype object because we can access typeinfo and sizeof.
    >
    > The allocation of memory alone does not create an array type object, it is
    > the declaration of an object using square brackets that creates the array
    > type object.


    --And I still don't know what you mean by array type object vs array
    --object. Until you explain that technical distinction to me, you're
    --literally just spouting effective nonsense, as you just invented those
    --terms and no one else knows what you're saying.

    Well consider the following:

    int arr[3]={0};
    std::cout<< arr;

    The above does not output an array object, it outputs a memory address.
    To output the array object you need to loop and dereference:

    for (int i=0; i<3; ++i){
    std::cout<< arr << std::endl;
    }

    The array type object is a region of memory that contains a value that is
    some memory address.
    The array object is a region of memory than contains three integer objects,
    each with the value 0.
     
    Paul, May 24, 2011
    #16
  17. Paul

    Paul Guest

    "Joshua Maurice" <> wrote in message
    news:...
    On May 24, 6:32 am, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    > --3- calls delete[] on a pointer of the wrong type and thus invokes UB,
    >
    > That is easily corrected by casting back , this is not a point important
    > to
    > the question.


    --Any dereference of that pointer, basically, is UB. There's no reason
    --to do the cast in the first place.

    What derefernecing any pointer in C++ is UB?
    Or just pointers to array type objects?

    I'm unsure what you are saying here, what do you think this pointer points
    to?
     
    Paul, May 25, 2011
    #17
  18. On May 24, 1:11 pm, "Paul" <> wrote:
    > "Ian Collins" <> wrote in message
    >
    > news:...
    >
    >
    >
    >
    >
    > > On 05/25/11 12:58 AM, Paul wrote:

    >
    > >>>>>> Ok in connection to my previous post, lets remove the null pointer
    > >>>>>> issue
    > >>>>>> and
    > >>>>>> consider this:

    >
    > >>>>>> #include<iostream>

    >
    > >>>>>> typedef int (*pparr)[3];

    >
    > >>>>>> int main(){
    > >>>>>>     pparr p1 = (pparr)new int[3];
    > >>>>>>     pparr p2= p1;
    > >>>>>>     delete[] p1;
    > >>>>>>     std::cout<<    *p2<<std::endl;

    >
    > >>>>> UB yet again.

    >
    > >>>>>>     std::cout<<    typeid(*p2).name();
    > >>>>>> }

    >
    > >>>>>> In the last 2 lines does an array type object exist, even though
    > >>>>>> there
    > >>>>>> is
    > >>>>>> no
    > >>>>>> array object?

    >
    > >>>>> No.

    >
    > >>>>>> If not what is the object that stores the address and is interpreted
    > >>>>>> as
    > >>>>>> an
    > >>>>>> array type by the typeid expression?

    >
    > >>>>> The typeid and sizeof operators do not evaluate their expression
    > >>>>> (unless
    > >>>>> in case of typeid the type is polymorphic).  So no object is required.

    >
    > >>>> You do not seem to understand the question.

    >
    > >>> You do not appear to understand the answer.

    >
    > >>>> I said ..if not what is the object that stores the address?
    > >>>> So what is this object? Do you know?

    >
    > >>> There isn't an object.  The compiler knows the type of *p2.  You may as
    > >>> well have written

    >
    > >>> #include<iostream>
    > >>> #include<typeinfo>

    >
    > >>> typedef int (*pparr)[3];

    >
    > >>> int main(){
    > >>>    pparr p2;
    > >>>    std::cout<<  typeid(*p2).name()<<  std::endl;
    > >>> }

    >
    > >> You are not addressing the what stores the memory address.

    >
    > > Because there isn't an address to store.  The typeid operator (like
    > > sizeof) works with types, not values.  In a simple case such as this the
    > > operand is not evaluated.  Until you understand this you will be stuck in
    > > limbo.

    >
    > > I could have simplified my simplification further by writing

    >
    > > std::cout << typeid(int[3]).name() << std::endl;

    >
    > > See?  No memory address just a type.

    >
    > There is an address stored.
    >
    > Look at the code :
    >
    > int main(){
    >  int (*pp)[3] = (int (*)[3])new int[3];
    >  std::cout<<*pp;}
    >
    > If this does not output an address what the hell is it?
    >
    > >> A memory address value is stored so there must be an object to store this
    > >> value, you say there is no object so what is it that stores this value?

    >
    > > There isn't an address.  Where's the address in typeid(int).name()?  Or
    > > sizeof(int)?

    >
    > The address is shown in my code above.
    > Have you lost your brain today?


    **** yeah! Your posts ROCK!!
     
    Oliver Jackson, May 25, 2011
    #18
  19. On May 24, 3:56 pm, "Paul" <> wrote:
    > "Joshua Maurice" <> wrote in message
    >
    > news:...
    > On May 24, 6:54 am, "Paul" <> wrote:
    >
    > > *p2 does not attempt to access the deallocated memory.

    >
    > --Doesn't matter. It's UB. Attempting to read the pointer, not the
    > --deallocated memory, is UB. At least it is according to the C spec, and
    > --I expect that the C++ standard will follow suit if it hasn't already
    >
    > This pointer obviously points to something that has a value that is
    > displayed on the screen as a memory address. It certainly doesn't point to
    > the integer objects that were allocated by new, so what does it point to?
    > How can you say it is UB if you do not first establish what it is pointing
    > to?


    Take the following program:
    #include <stdlib.h>
    #include <stdio.h>
    int main()
    { char* a = (char*)malloc(1);
    char* b = a;
    free(a);
    printf("%p\n", b);
    }
    This program has UB in C, and as I said will likely have UB in C++, or
    it already is UB in C++. See the defect report for more details:

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm

    > --And I still don't know what you mean by array type object vs array
    > --object. Until you explain that technical distinction to me, you're
    > --literally just spouting effective nonsense, as you just invented those
    > --terms and no one else knows what you're saying.
    >
    > Well consider the following:
    >
    > int arr[3]={0};
    > std::cout<< arr;
    >
    > The above does not output an array object, it outputs a memory address.
    > To output the array object you need to loop and dereference:
    >
    > for (int i=0; i<3; ++i){
    > std::cout<< arr << std::endl;
    >
    > }
    >
    > The array type object is a region of memory that contains a value that is
    > some memory address.
    > The array object is a region of memory than contains three integer objects,
    > each with the value 0.


    I suggest you take a course in compilers, or read a book, like one of
    the Dragon Books, Red or Green. You have gross misunderstandings of
    both the C++ object model, and how compilers actually generate code.
    There is no such thing as an "array-type object", as you've defined
    it. In these examples, there are only array objects and pointer
    objects - including pointers to arrays and pointers to individual
    elements, not "array-type objects".

    Consider:
    void foo()
    { int x[3];
    int* y = x;
    cout << y;
    }

    "x" is a piece of text. It is a preprocessor token. It is an
    identifier for an auto (stack) variable. It names an object. It names
    an (array) object of type "int [3]". That array object has three sub-
    objects of type "int".

    "y" is a piece of text. It is a preprocessor token. It is an
    identifier for an auto (stack) variable. It names an object. It names
    a (pointer) object of type "int*". It holds the address of the first
    element of the auto (stack) array x.

    This function "uses" the following objects:
    - the array object x, and its 3 unnamed int sub-objects,
    - the pointer object y,
    - the object cout.
    There is no "array-type object".

    There is no such thing as the array-type object. A common compiler
    (and one which has sizeof(int) == 4) will implement this function by:
    - allocating the stack space,
    - taking the stack pointer and adding 0 to get the address of the
    first element of the array object x,
    - taking the stack pointer and adding 12 to get the address of the
    pointer object y,
    - storing the address of the first element of the array object x into
    the object y, (we previously obtained both addressed - see above), (or
    it'll put it into a register, or both, depending on the particulars
    and how the compiler wants to use registers),
    - set up the state required to call "std::eek:perator<<" according to the
    calling-convention, which includes putting the value of the pointer
    object y in memory a certain offset from the stack pointer register
    value, or in a particular register,
    - calling a jump instruction or some such to call function
    "std::eek:perator<<",
    - reading the return value of that function from a calling-convention
    location, such as a particular register or from memory at a particular
    offset from the stack pointer register value,
    - and so on.

    Consider the function:
    void foo()
    { int* x = new int[3];
    cout << x;
    }

    "x" is a piece of text. It is a preprocessor token. It is an
    identifier for an auto (stack) variable. It names an object. It names
    a (pointer) object of type "int*". It holds a value of the address of
    the first element of the unnamed dynamically allocated array.

    This function "uses" the following objects:
    - the pointer object x,
    - the object cout,
    - the unnamed, dynamically allocated, array object.
    - the 3 unnamed int sub-objects of the unnamed, dynamically allocated,
    array object.
    There is no "array-type object".

    A common compiler will implement this function by:
    - allocating the stack space,
    - taking the stack pointer and adding 0 to get the address of the
    pointer object x,
    - set up the state required to call the new operator according to the
    calling-convention, which includes putting the value 3 in memory a
    certain offset from the stack pointer register value, or in a
    particular register,
    - reading the return value of that function from a calling-convention
    location, such as a particular register or from memory at a particular
    offset from the stack pointer register value,
    - storing the return result of the function call, aka "new int[3]",
    aka a pointer to the first element of the dynamically allocated array,
    into the pointer object x, (we previously obtained its addressed - see
    above), (or it'll put it into a register, or both, depending on the
    particulars and how the compiler wants to use registers),
    - and then it will call "std::eek:perator<<" just like it in the earlier
    example,
    - and so on.
     
    Joshua Maurice, May 25, 2011
    #19
  20. Paul

    Ian Collins Guest

    On 05/25/11 08:11 AM, Paul wrote:
    > "Ian Collins"<> wrote:
    >> On 05/25/11 12:58 AM, Paul wrote:
    >>>>
    >>> You are not addressing the what stores the memory address.

    >>
    >> Because there isn't an address to store. The typeid operator (like
    >> sizeof) works with types, not values. In a simple case such as this the
    >> operand is not evaluated. Until you understand this you will be stuck in
    >> limbo.
    >>
    >> I could have simplified my simplification further by writing
    >>
    >> std::cout<< typeid(int[3]).name()<< std::endl;
    >>
    >> See? No memory address just a type.
    >>

    >
    > There is an address stored.
    >
    > Look at the code :
    >
    > int main(){
    > int (*pp)[3] = (int (*)[3])new int[3];
    > std::cout<<*pp;
    > }
    > If this does not output an address what the hell is it?


    The value returned by new.

    >>> A memory address value is stored so there must be an object to store this
    >>> value, you say there is no object so what is it that stores this value?

    >>
    >> There isn't an address. Where's the address in typeid(int).name()? Or
    >> sizeof(int)?
    >>

    > The address is shown in my code above.


    The address in your code id the value return by new. No amount of
    casting will change that.

    > Have you lost your brain today?


    Oh how mature you are.

    --
    Ian Collins
     
    Ian Collins, May 25, 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. Roger Kjærnsrød
    Replies:
    1
    Views:
    475
    Peter Blum
    Sep 21, 2004
  2. JustMe
    Replies:
    0
    Views:
    436
    JustMe
    Oct 4, 2004
  3. Tarun Mistry
    Replies:
    1
    Views:
    2,131
  4. xyZed
    Replies:
    3
    Views:
    1,372
    Jacqui or (maybe) Pete
    Jun 29, 2003
  5. Developwebsites

    who lets these people on the net?...

    Developwebsites, Aug 31, 2004, in forum: HTML
    Replies:
    27
    Views:
    877
    kchayka
    Sep 1, 2004
Loading...

Share This Page