delete[] p or delete[] *p

G

Goran

If I call delete[] on int*, it's no different to int (*)[size]? Or is it?

You are repeatedly trying to get into UB land. You should __not__ ask
the question you are asking. You never allocated int (*)[size]. Can't
do that, perhaps because of array type erasure: as soon as the array
type hits operator new, array type is erased and new sees a pointer (a
double one, "**", but nonetheless). You never got an __array__ out of
new, and you can't pass an array to delete.

If you have TYPE* that you need to delete, you must know how you
allocated it, end of. If you did p = new TYPE(), you do delete p; if
you did p = new TYPE[1], you do delete [] p; (yes, even if you put 1
in []). If you did p = new TYPE(*)[1], you do delete [] p (but, p's
type is TYPE**).
How does the compiler know how many destructors to call?

Not ours to know (hint: implementation's heap management internals
serve for that).
And what if call delete[] *(int (*)[size])? Is it implicitly converted to
int*?

I'd wager yes, due to array-type-erasure. But you did not __allocate__
that, now did you? (That is, you have some other problem in your code,
so this question should not be asked in the first place).

Goran.
 
P

Paul

Goran said:
If I call delete[] on int*, it's no different to int (*)[size]? Or is it?

You are repeatedly trying to get into UB land. You should __not__ ask
the question you are asking. You never allocated int (*)[size]. Can't
do that, perhaps because of array type erasure: as soon as the array
type hits operator new, array type is erased and new sees a pointer (a
double one, "**", but nonetheless). You never got an __array__ out of
new, and you can't pass an array to delete.
What do you mean the array-type hits operator new its array-type is erased?
There never is an array-type the C runtime will return a pointer to int, not
some array-object-type.

If you have TYPE* that you need to delete, you must know how you
allocated it, end of. If you did p = new TYPE(), you do delete p; if
you did p = new TYPE[1], you do delete [] p; (yes, even if you put 1
in []). If you did p = new TYPE(*)[1], you do delete [] p (but, p's
type is TYPE**).

The type is the same , both int type arrays, only the level of dereference
is different for example:

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

How does the compiler know how many destructors to call?

Not ours to know (hint: implementation's heap management internals
serve for that).
And what if call delete[] *(int (*)[size])? Is it implicitly converted to
int*?
I'd wager yes, due to array-type-erasure. But you did not __allocate__
that, now did you? (That is, you have some other problem in your code,
so this question should not be asked in the first place).

I don't know this term "array type erasure". What do you mean by that?
 
G

Goran

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.
I don't know this term "array type erasure". What do you mean by that?

FAQ uses term "decay". I meant same thing (that was the term used to
explain the thing to me).

Goran.
 
P

Paul

Goran said:
int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB. The standard specifically states that
the pointer returned from new must be castable.
Consider this more complex example:
class Base{
public:
Base() {std::cout<<"Constructing base\n";}
virtual ~Base(){std::cout<<"Destructing base\n";}
};

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

int main() {
Base (*p2)[3] = (Base (*)[3])new Derived[2][3];
delete[] p2;
}

The cast is required , otherwise you'd need to loop through the array
columns for allocation and deallocation..
I could cast it back prior to deletion with:
delete[] (Derived (*)[3])p2;

But this is unneccessary because Base type is an acceptable pointer type.
The type is only neccessay for the correct destruction of objects. For
example:
Base *p2 = new Derived[3];
delete[] p2;

is identical to
Base (*p2)[3] = (Base (*)[3])new Derived[3];
deletep[] p2;

The type that is relevant here is that it is Base or Derived, the number of
elements destructed is decided by the C runtime. As long as the dereferenced
pointer passed to delete has the same value as the pointer returned by new
all is ok, because it is converted to void* anyway. The C runtime decides
whether it deletes 3 objects or 1 , not the type system.
If int[3] and int* both point to the same address, then converted to void*
they are identical.
The C++ type system is only interested in if its an array of int-typ,
Derived-type , or Base-type, It not up to the type system to deicde how many
destructors to call.

It would be UB if you converted the pointer to a different type altogether
for example:
double* p = (double*)new int[6];
delete[] p;
This would be UB , because you are converting to a new type of array..
FAQ uses term "decay". I meant same thing (that was the term used to
explain the thing to me).

Ok I see you are talking about implicit pointer conversion.

HTH
Paul.
 
K

Kai-Uwe Bux

Paul said:
Goran said:
int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB.

We shall see.
The standard specifically states that the pointer returned from new must
be castable.

Correct: [5.2.10/7] states:

A pointer to an object can be explicitly converted to a pointer to an
object of different type.65) Except that converting an rvalue of type
"pointer to T1" to the type "pointer to T2" (where T1 and T2 are object
types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified.

That implies that after casting, you have an unspecified result. The only
thing you can do with it, is casting back, and even that presupposes
compatible alignment requirement.

In particular, passing the unspecified value obtained by casting to delete
or delete [] is undefined behavior.

Consider this more complex example:
class Base{
public:
Base() {std::cout<<"Constructing base\n";}
virtual ~Base(){std::cout<<"Destructing base\n";}
};

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

int main() {
Base (*p2)[3] = (Base (*)[3])new Derived[2][3];
delete[] p2;
}

The cast is required , otherwise you'd need to loop through the array
columns for allocation and deallocation..
I could cast it back prior to deletion with:
delete[] (Derived (*)[3])p2;

But this is unneccessary because Base type is an acceptable pointer type.

What do you mean by "acceptable"?

Also, the value of the variable p2 is _unspecified_ as it is obtained
through casting.
The type is only neccessay for the correct destruction of objects. For
example:
Base *p2 = new Derived[3];
delete[] p2;

is identical to
Base (*p2)[3] = (Base (*)[3])new Derived[3];
deletep[] p2;

The type that is relevant here is that it is Base or Derived, the number
of elements destructed is decided by the C runtime. As long as the
dereferenced pointer passed to delete has the same value as the pointer
returned by new all is ok, because it is converted to void* anyway. The C
runtime decides whether it deletes 3 objects or 1 , not the type system.

Sameness of value is not guaranteed by the standard (pretending we know what
it means). Consider:

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( p1 == p2 );
}

This does not even compile as p1 and p2 are of different type.
If int[3] and int* both point to the same address, then converted to void*
they are identical.

So this is what we mean by "sameness of values". Ok, let's consider

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( (void*)p1 == (void*)p2 );
}

Now, the code compiles. However, contrary to expectations, the assert is
allowed to _fail_ because the value of p2 is unspecified. In fact, using the
unspecified value as an argument for a cast is UB. So, we could do:

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( p2 == (Base (*) [3]) p1 );
}

This looks as though it could not fail. However, the two sides of the == are
both unspecified values. It is neither clear that they are equal nor that
comparing them does not result in a core dump.

If you see more guarantees in the standard that would render any of the
above defined behavior, please cite them.

[...]


Best,

Kai-Uwe Bux
 
P

Paul

Kai-Uwe Bux said:
Paul said:
Goran said:
int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB.

We shall see.
The standard specifically states that the pointer returned from new must
be castable.

Correct: [5.2.10/7] states:

A pointer to an object can be explicitly converted to a pointer to an
object of different type.65) Except that converting an rvalue of type
"pointer to T1" to the type "pointer to T2" (where T1 and T2 are object
types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified.

That implies that after casting, you have an unspecified result. The only
thing you can do with it, is casting back, and even that presupposes
compatible alignment requirement.
But I didn't cast to a different object type, I casted to an array of
objects of the same type.
That quote is talking about converting between objects of a different types.

In particular, passing the unspecified value obtained by casting to delete
or delete [] is undefined behavior.

What is unspecified , the cast does not make the pointer *unspecified*
Consider this more complex example:
class Base{
public:
Base() {std::cout<<"Constructing base\n";}
virtual ~Base(){std::cout<<"Destructing base\n";}
};

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

int main() {
Base (*p2)[3] = (Base (*)[3])new Derived[2][3];
delete[] p2;
}

The cast is required , otherwise you'd need to loop through the array
columns for allocation and deallocation..
I could cast it back prior to deletion with:
delete[] (Derived (*)[3])p2;

But this is unneccessary because Base type is an acceptable pointer type.

What do you mean by "acceptable"?
Acceptable pointer type, that is a base(with virtual destructor) or derived
class. There are probably many other acceptable pointer conversions which
are Implementation specific e.g: short to int where they are both the same
size.
Also, the value of the variable p2 is _unspecified_ as it is obtained
through casting.
Casting doesn't make it *unspecified*.
The type is only neccessay for the correct destruction of objects. For
example:
Base *p2 = new Derived[3];
delete[] p2;

is identical to
Base (*p2)[3] = (Base (*)[3])new Derived[3];
deletep[] p2;

The type that is relevant here is that it is Base or Derived, the number
of elements destructed is decided by the C runtime. As long as the
dereferenced pointer passed to delete has the same value as the pointer
returned by new all is ok, because it is converted to void* anyway. The C
runtime decides whether it deletes 3 objects or 1 , not the type system.

Sameness of value is not guaranteed by the standard (pretending we know
what
it means). Consider:

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( p1 == p2 );
}

This does not even compile as p1 and p2 are of different type.

That doesn't mean the values are not the same though does it.
If int[3] and int* both point to the same address, then converted to
void*
they are identical.

So this is what we mean by "sameness of values". Ok, let's consider

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( (void*)p1 == (void*)p2 );
}

Now, the code compiles. However, contrary to expectations, the assert is
allowed to _fail_ because the value of p2 is unspecified. In fact, using
the
unspecified value as an argument for a cast is UB. So, we could do:

I don't know what your problem is with understand the meaning of two of the
same values.
its simple:
float f = 65;
int x = 65;
long l = 65;

same values.

int main () {
Derived (*p1) [3] = new Derived [2][3];
Base (*p2) [3] = (Base (*)[3]) p1;
assert( p2 == (Base (*) [3]) p1 );
}

This looks as though it could not fail. However, the two sides of the ==
are
both unspecified values. It is neither clear that they are equal nor that
comparing them does not result in a core dump.

I don't have a clue what you are talking about, what is an unspecified
value? What fails?

A pointers' value is the address it points to , if two pointers point to the
same address they have they same value, simple as that.
If you see more guarantees in the standard that would render any of the
above defined behavior, please cite them.
What guarantees you talknig about here?
 
G

Goran

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;
What is the difference with the above deletes?
As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB. The standard specifically states that
the pointer returned from new must be castable.

Return type of "new int(*)[5]" is int**. You cast that into int(*)[5],
using C cast. That, as far as I can see, ends up in same effect as
reinterpret_cast, and reinterpret_cast is UB (or platform specific at
best).
Consider this more complex example:
class Base{
public:
 Base() {std::cout<<"Constructing base\n";}
 virtual ~Base(){std::cout<<"Destructing base\n";}

};

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

};

int main() {
 Base (*p2)[3] = (Base (*)[3])new Derived[2][3];
 delete[] p2;

}

The cast is required ,  otherwise you'd need to loop through the array
columns for allocation and deallocation..

First, the cast is not required, because

Derived (*p2)[3] = new Derived[2][3];
delete [] p2;

works just as well.

Second, the problem with your exact example is that in practice just
does not work. And I mean, at all!

Try this:

class Base{
public:
Base() : i(0) {}
int i;
};

class Derived: public Base{
public:
Derived() : j(1) {}
int j;
};

Base (*p2)[3] = (Base (*)[3])new Derived[2][3];
const Base& b = p2[0][1];
assert(0 == b.i); // Fires on common implementations
assert(1 == b.i); // Does not fire on common implementations. Eh!?

Of course, problem is that pointer returned by "new Derived[2][3]" and
"Base (*)[3]" have unrelated types, and my code snippet shows why that
is required.

Goran.
Ok I see you are talking about implicit pointer conversion.

Nice try ;-);

Goran.
 
K

Kai-Uwe Bux

Paul said:
Kai-Uwe Bux said:
Paul said:
int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB.

We shall see.
The standard specifically states that the pointer returned from new must
be castable.

Correct: [5.2.10/7] states:

A pointer to an object can be explicitly converted to a pointer to an
object of different type.65) Except that converting an rvalue of type
"pointer to T1" to the type "pointer to T2" (where T1 and T2 are object
types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified.

That implies that after casting, you have an unspecified result. The only
thing you can do with it, is casting back, and even that presupposes
compatible alignment requirement.
But I didn't cast to a different object type, I casted to an array of
objects of the same type.
That quote is talking about converting between objects of a different
types.
[...]

Ok, so you are saying that the C-style cast you are using is _not_ governed
by clause [5.2.10/7]. Please specify which clause of the standard you are
relying on in determining the behavior of the cast expression.


Best,

Kai-Uwe Bux
 
K

Kai-Uwe Bux

Here is a data point:

#include <iostream>

class BaseA{
public:
int k;
BaseA() {std::cout<<"Constructing base a\n";}
virtual ~BaseA(){std::cout<<"Destructing base a\n";}
};

class BaseB {
public:
int i;
BaseB() {std::cout<<"Constructing base b\n";}
virtual ~BaseB(){std::cout<<"Destructing base b\n";}
};

class Derived: public BaseA, BaseB {
public:
int j;
Derived() {std::cout<<"Constructing derived\n";}
~Derived(){std::cout<<"Destructing derived\n";}
};

int main() {
Derived (*p1) [3] = new Derived [2][3];
BaseB (*p2)[3] = (BaseB (*)[3])p1;
delete [] p2;
}

This program segfaults on my machine.

I think, it is allowed to do so.


Best,

Kai-Uwe Bux
 
P

Paul

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;
What is the difference with the above deletes?
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB. The standard specifically states
that
the pointer returned from new must be castable.

Return type of "new int(*)[5]" is int**. You cast that into int(*)[5],
using C cast. That, as far as I can see, ends up in same effect as
reinterpret_cast, and reinterpret_cast is UB (or platform specific at
best).

So, as far as you can see, any use of a c-style cast will immediately cause
UB?

Of course, problem is that pointer returned by "new Derived[2][3]" and
"Base (*)[3]" have unrelated types, and my code snippet shows why that
is required.

Your code shows me nothing except that you are a noob who uses assert, If
you want to expalin something to me in code please don't use noob statements
like assert.
Ok I see you are talking about implicit pointer conversion.

Nice try ;-);

What does this mean? What am I trying to do in your mind?

Sorry for snipping etc but dont have time to manually indent all that crap.
 
P

Paul

Kai-Uwe Bux said:
Here is a data point:

#include <iostream>

class BaseA{
public:
int k;
BaseA() {std::cout<<"Constructing base a\n";}
virtual ~BaseA(){std::cout<<"Destructing base a\n";}
};

class BaseB {
public:
int i;
BaseB() {std::cout<<"Constructing base b\n";}
virtual ~BaseB(){std::cout<<"Destructing base b\n";}
};

class Derived: public BaseA, BaseB {
public:
int j;
Derived() {std::cout<<"Constructing derived\n";}
~Derived(){std::cout<<"Destructing derived\n";}
};

int main() {
Derived (*p1) [3] = new Derived [2][3];
BaseB (*p2)[3] = (BaseB (*)[3])p1;
delete [] p2;
}

This program segfaults on my machine.

I think, it is allowed to do so.


Best,
I will need to look at this later when I have more time. As this is a
different inheritance pattern maybe there are some isssues
 
P

Paul

Kai-Uwe Bux said:
Paul said:
Kai-Uwe Bux said:
Paul wrote:


int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;

What is the difference with the above deletes?

As far as I am concerned, difference is: first two are UB (platform-
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.

Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB.

We shall see.

The standard specifically states that the pointer returned from new
must
be castable.

Correct: [5.2.10/7] states:

A pointer to an object can be explicitly converted to a pointer to an
object of different type.65) Except that converting an rvalue of type
"pointer to T1" to the type "pointer to T2" (where T1 and T2 are object
types and where the alignment requirements of T2 are no stricter than
those of T1) and back to its original type yields the original pointer
value, the result of such a pointer conversion is unspecified.

That implies that after casting, you have an unspecified result. The
only
thing you can do with it, is casting back, and even that presupposes
compatible alignment requirement.
But I didn't cast to a different object type, I casted to an array of
objects of the same type.
That quote is talking about converting between objects of a different
types.
[...]

Ok, so you are saying that the C-style cast you are using is _not_
governed
by clause [5.2.10/7]. Please specify which clause of the standard you are
relying on in determining the behavior of the cast expression.
I was saying the cast wasn't an issue with me, I don't see things in such a
way that every cast produces UB.
A cast from int* to int*[] doesn't seem like a major conversion of any
major concern to me.
 
G

Goran

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;
What is the difference with the above deletes?
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.
Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB. The standard specifically states
that
the pointer returned from new must be castable.
Return type of "new int(*)[5]" is int**. You cast that into int(*)[5],
using C cast. That, as far as I can see, ends up in same effect as
reinterpret_cast, and reinterpret_cast is UB (or platform specific at
best).

So, as far as you can see, any use of a c-style cast will immediately cause
UB?

Not will. Could. Your cast up there __will__, however (and a very
simple example has shown that).
Of course, problem is that pointer returned by "new Derived[2][3]" and
"Base (*)[3]" have unrelated types, and my code snippet shows why that
is required.

Your code shows me nothing except that you are a noob who uses assert, If
you want to expalin something to me in code please don't use noob statements
like assert.

First, assert is not a statement, it's a function. Second, it's use is
incidental to the problem. Noob or not, assert shows that your cast
does not work.

In slightly more detail: in common implementations, object's memory
layout is such that your cast, on your example, fails horribly. Line

const Base& b = p2[0][1];

does not produce a reference to b (and it should). It does not do it,
because the cast on the line where new is called is __wrong__.

In even more detail: what new allocated (on common implementations) is
6 consecutive instances of Derived. So let's presume a 32-bit platform
and a common implementation. New gives (memory layout):

32 bits: Base.i
32 bits: Derived.j
32 bits: Base.i
32 bits: Derived.j
.... 6 of those in total

You tried to cast that to (memory layout on common implementations):

32 bits: Base.i
32 bits: Base.i
.... 6 of those in total

Your cast causes "b" to "reference" Derived.j, which makes no sense
whatsoever. "assert" was only there to show you this. I hoped not so
many words were needed, but alas...

Goran.
 
P

Paul

int (*p1)[5] = (int (*)[5])new int*[5]; /*2d array*/
int (*p2)[5] = (int (*)[5])new int[5]; /*1d array*/
int (*p3)[5] = new int[5][5]; /*2d array*/
delete[] p1;
delete[] p2;
delete[] p3;
What is the difference with the above deletes?
specific at best), because of wrong casts in corresponding "new",
whereas the third one is correct.
Why are they UB? After having a read through the rellevant pages of the
standard I don't think that it is UB. The standard specifically states
that
the pointer returned from new must be castable.
Return type of "new int(*)[5]" is int**. You cast that into int(*)[5],
using C cast. That, as far as I can see, ends up in same effect as
reinterpret_cast, and reinterpret_cast is UB (or platform specific at
best).

So, as far as you can see, any use of a c-style cast will immediately
cause
UB?

Not will. Could. Your cast up there __will__, however (and a very
simple example has shown that).

------------------------------------------

Who the hell do you think you are ?
You cant even communicate properly I cant be arsed with arseholes who cant
communicate properly.
Im not gonna bother indenting and making an effort for someone who obviously
thinks he is abov eme.

I told you your example showed me nothing except that you are some noob who
uses *STATEMENTS* like assert
 
G

Goran

I told you your example showed me nothing except that you are some noob who
uses *STATEMENTS* like assert

I was mistaken, I apologize. assert is not a function, it's rather a
macro.

It's not a statement though. Please refer to section 6 of the current
language standard for more detail on what a statement is.

Goran.
 
P

Paul

I told you your example showed me nothing except that you are some noob
who
uses *STATEMENTS* like assert

I was mistaken, I apologize. assert is not a function, it's rather a
macro.

It's not a statement though. Please refer to section 6 of the current
language standard for more detail on what a statement is.


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

I dont care what its called in the standards I called it a statement and you
knew what i meant.
What I dont understand is what exactly your argument is, you fail to
communicate properly.
You said something was UB but no expalanation, just because it appeared to
be UB to you.
Now you are blabbing on about some assert thing. WHat exactly has all this
got to do with delete[] ?
 
P

Paul

Kai-Uwe Bux said:
Here is a data point:

#include <iostream>

class BaseA{
public:
int k;
BaseA() {std::cout<<"Constructing base a\n";}
virtual ~BaseA(){std::cout<<"Destructing base a\n";}
};

class BaseB {
public:
int i;
BaseB() {std::cout<<"Constructing base b\n";}
virtual ~BaseB(){std::cout<<"Destructing base b\n";}
};

class Derived: public BaseA, BaseB {
public:
int j;
Derived() {std::cout<<"Constructing derived\n";}
~Derived(){std::cout<<"Destructing derived\n";}
};

int main() {
Derived (*p1) [3] = new Derived [2][3];
BaseB (*p2)[3] = (BaseB (*)[3])p1;
delete [] p2;
}

This program segfaults on my machine.

I think, it is allowed to do so.
Ok I had a quick look at this.
This works perfectly ok on my machine. So are you are saying is that its UB
to cast a pointer to Derived into a pointer to BaseB?
Or are you saying that its only UB to cast a pointer of Derived (*)[size] to
BaseB (*)[size], but its ok to cast a Derived* to a baseB*?
As far as I was aware is perfectly ok to downcast to a Base class. As long
as the Base class has a virtual destructor the object destruction will
destruct the whole Dervied object.
 
G

Goran

What I dont understand is what exactly your argument is, you fail to
communicate properly.
You said something was UB but no expalanation, just because it appeared to
be UB to you.
Now you are blabbing on about some assert thing. WHat exactly has all this
got to do with delete[] ?

Your cast is on the new side invokes UB. By consequence, your examples
are buggy, and so is your call to operator[].

You do not seem to accept that cast invokes UB, so I made you a piece
of code that shows why your cast is, and should be, UB.

For that piece of code, I used assert to ascertain what should be true
(that "0" equals "b.i"). If you compile this snippet without NDEBUG,
"assert(0 == b.i)" should not fire, because, clearly, Base() sets i to
0. And yet, this assert does fire (on common implementations). Why?
Because your cast invoked UB. Consequently, everything else is wrong,
including delete[] you're trying to pull off.

Goran.
 
P

Paul

Leigh Johnston said:
Casting from derived to base is called "upcasting" not "downcasting".
Thats a rather back to front way of looking at it. Casting to a subobject is
casting up?
 
P

Paul

What I dont understand is what exactly your argument is, you fail to
communicate properly.
You said something was UB but no expalanation, just because it appeared to
be UB to you.
Now you are blabbing on about some assert thing. WHat exactly has all this
got to do with delete[] ?

Your cast is on the new side invokes UB. By consequence, your examples
are buggy, and so is your call to operator[].
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Why?
Please explain why it is UB?

Any time we cast in C++ we produce UB?
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

You do not seem to accept that cast invokes UB, so I made you a piece
of code that shows why your cast is, and should be, UB.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Your code doesn't prove the cast is UB. I would accept it if it is UB but as
far as I can see all the standard says is that new must return a castable
pointer, this implies that its allowed to be casted.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

For that piece of code, I used assert to ascertain what should be true
(that "0" equals "b.i"). If you compile this snippet without NDEBUG,
"assert(0 == b.i)" should not fire, because, clearly, Base() sets i to
0. And yet, this assert does fire (on common implementations). Why?
Because your cast invoked UB.
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Eh? Because you code asserts something to be not equal you assert this to
mean the cast produces UB? How do you come to that conclusion?
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top