Topic: Correctness of compilers behavior


Author: "john (j.d.) hickin" <hickin@bnr.ca>
Date: 1996/02/14
Raw View
|> for (unsigned i=0; i<size; ++i) {
|>     (bptr+i)->~B();
|>     new(aptr+i) A;
|>   }

I think this should be two loops, the first running backwards to destroy the
B's and the second running forwards to create the A's.


|>  delete [] arr;

'delete p' and 'delete[] p' where 'p = new(...) whatever' may be undefined.

--
John Hickin      Nortel Technology, Montreal, Quebec
(514) 765-7924   hickin@bnr.ca
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy is
  in http://reality.sgi.com/employees/austern_mti/std-c++/policy.html. ]





Author: Ian T Zimmerman <itz@rahul.net>
Date: 1996/02/20
Raw View
In article <4g3i93$9lp@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
(Fergus Henderson) writes:

>
> "Constantine Antonovich:" <const@Orbotech.Co.IL> writes:
>
>
> >  for (unsigned i=0; i<size; ++i) {
> >    (bptr+i)->~B();
> >    new(aptr+i) A;
> >  }
> >

> >int main(void)
> >{
> >  A* arr=foo(2);
> >  delete [] arr;
>
> This has undefined behaviour.  It contravenes 5.3.5[expr.delete]/2, which
> says that the expression passed to `delete []' must be a pointer to the
> first element of an array of objects allocated with `new []'; this is not
> the case, because although there once was such an array at that memory
> location, its lifetime ended when the memory was overwritten by the calls
> to placement new (see 3.8[basic.life]/1).
>

Is it relevant here that A and B are unrelated classes? What about the
following code?

A a;

A* as = new A [10];

for (int i = 0; i < 10; ++i) {
    new (&as[i]) A(a);
}
delete [] as;

If this is undefined, how else can I initialize array members with a
nondefault constructor?

Thanks in advance,

--
Ian T Zimmerman            +-------------------------------------------+
P.O. Box 13445             I    With so many executioners available,   I
Berkeley, California 94712 I suicide is a really foolish thing to do.  I
USA  <itz@rahul.net>       +-------------------------------------------+
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std.c++-request@ncar.ucar.edu
]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/02/20
Raw View
In article UAA01735@kronstadt.rahul.net, Ian T Zimmerman <itz@rahul.net> writes:
>In article <4g3i93$9lp@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU
>(Fergus Henderson) writes:
>
>> >  for (unsigned i=0; i<size; ++i) {
>> >    (bptr+i)->~B();
>> >    new(aptr+i) A;
>> >  }
>> >
>
>> >int main(void)
>> >{
>> >  A* arr=foo(2);
>> >  delete [] arr;
>>
>> This has undefined behaviour.  It contravenes 5.3.5[expr.delete]/2, which
>> says that the expression passed to `delete []' must be a pointer to the
>> first element of an array of objects allocated with `new []'; this is not
>> the case, because although there once was such an array at that memory
>> location, its lifetime ended when the memory was overwritten by the calls
>> to placement new (see 3.8[basic.life]/1).
>
>Is it relevant here that A and B are unrelated classes?

No. It only matters that A and B are not the same type. If A were derived
from B or vice-versa the code would still be wrong. Example:
 class A : public B { ... };
 B* p = new A[10]; // legal, but a bad idea
 delete[] p; // error that does not have to be diagnosed

Such code is valid for single objects, but not for arrays. Although an A
is-a B, an array of A is NOT an array of B. Ordinarily you don't want
C-style arrays of objects, especially polymorphic objects. You probably
want an array of pointers so that you get object instead of value semantics,
or an array class of values to avoid the inconvenient properties of C-style
arrays.

>What about the following code?
>
>A a;
>
>A* as = new A [10];
>
>for (int i = 0; i < 10; ++i) {
>    new (&as[i]) A(a);
>}
>delete [] as;

It is valid to construct an object on top of the storage previously
used for another object of the same type, so this code is mostly OK.
Notice that you don't destroy the objects that were constructed with
the default constructor.

In the general case you would want to destroy the original objects
before building new objects in their storage locations. Related to
this point, the compiler will construct the original objects from
index 0 up to index 9, and will destroy them in the reverse order.
If the objects have any inter-dependencies, you might need to
mimic that behavior to ensure a valid program. So you might write:

 A* as = new A[10]; // construct as[0] through as[9] in that order
 for( int i=10; --i>=0; )
  as[i]->~A(); // destroy in reverse order
 for( int i=0; i<10; ++i )
  new (&as[i]) A(a); // contruct from as[0] through as[9]
 ...
 delete[] as; // destroys as[9] down to as[0]

If all you want is an array of values, you don't have to go through the
extra construction and destruction if the number of elements is known
at compile time:
 A as[10] = { a, a, a, a, a, a, a, a, a, a };
or perhaps
 A as[10] = { A(arg0), A(arg1), A(arg2), ... , A(arg9) };
to get different values in different slots.

---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ To submit articles: Try just posting with your newsreader.  If that fails,
                      use mailto:std-c++@ncar.ucar.edu
  FAQ:    http://reality.sgi.com/employees/austern_mti/std-c++/faq.html
  Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html
  Comments? mailto:std-c++-request@ncar.ucar.edu
]