1

I was thinking about how to solve this problem with placement new, and I faced a problem.

Suppose, that I allocate a float array:

float *f = new float[10];

Then, I use this storage to store doubles (note that I assume that f is properly aligned, and sizeof(float)*2==sizeof(double)), which destroys the float array:

double *d = new(f) double;
for (int i=1; i<5; i++) {
    new(d+i) double;
}

Now, is there a way to recreate the float array? The most intuitive solution

f = new(f) float[10];

may not work, as new[] can have a space overhead, so float[10] may not fit into f.

geza
  • 28,403
  • 6
  • 61
  • 135
  • 1
    What does "recreate" mean? You wish to be able to read the old float values? Or do you just want to scrap the double array and have a float array? – Justin Jul 11 '18 at 18:01
  • @Justin: No. As placement `new double` "destroyed" `f`'s original type, I'd like to `f` to have a float array type again. – geza Jul 11 '18 at 18:04
  • 1
    Possible duplicate of [Can placement new for arrays be used in a portable way?](https://stackoverflow.com/questions/15254/can-placement-new-for-arrays-be-used-in-a-portable-way) – Sneftel Jul 11 '18 at 18:46
  • The best reason you ask this is it's an XY problem. With the benefit of doubt, I consider this question unclear. Please state what you want to accomplish. – too honest for this site Jul 11 '18 at 18:59
  • @Olaf: I've described the background in the first sentence. It is absolutely plausible, that one wants to create a function, which has `float *` input/output, and the function wants to use this buffer as a temporary buffer to store doubles to avoid unnecessary allocation. Not an XY problem. – geza Jul 11 '18 at 19:18
  • Can't you use a loop as you did with the doubles ? – Michael Doubez Jul 11 '18 at 19:27
  • 1
    Which function? There is no function shown in your code. It seems more like a fundamental missunderstanding of the `new` operator and language basics. But thanks for removing my doubts. – too honest for this site Jul 11 '18 at 19:29
  • @MichaelDoubez: no, because it wouldn't make it a float array, but floats sitting next to each other. These are not the same. – geza Jul 11 '18 at 19:36
  • They were floats sitting next to each other. The overhead area is before the position the pointer points to. That hasn't changed. Truth to tell, it is hardly necessary, I doubt any compiler runs a destructor on integral types and even less that it would choke on an illegal float representation. – Michael Doubez Jul 11 '18 at 19:43
  • @MichaelDoubez: yes, considering practice, you are right. But this question is more about the standard, which for some reason, not that strict about this matter, allows overhead, which even can be differing size for each new[] call. – geza Jul 11 '18 at 19:49
  • Ok but then, reintepret_cast your double* to float* an do a placement new on each element and you'll get the same original state. – Michael Doubez Jul 11 '18 at 19:52
  • @MichaelDoubez: yes, that would be a logical thing to do, but I don't think that I'll get the same state. As I've said, an array is not just objects sitting next to each other. `new(f) float[2];` differs from `new(f) float; new(f+1) float;`. – geza Jul 11 '18 at 20:07
  • We are still paying the decision to not make array first class citizen but not that much. The standard guarantees you the contiguity of member (albeit with padding) in arrays. This is true whether the array is allocated on the stack or by new. The only twist is the overhead to relate the number of object between new[] and delete[] (plus whatever is needed by implementation). But placement new of single object doesn't have the overhead and memory area referenced by pointer offset can hold them. I don't see how you come up with additional constraints. – Michael Doubez Jul 11 '18 at 20:19
  • What does it mean to "destroy" the type of the array? Isn't `f` still `float*` no matter what you do with it? – hegel5000 Jul 11 '18 at 20:20
  • @MichaelDoubez: for example, you cannot index a pointer, if it is not pointing to an actual array. So, if `f` points to two consecutive floats, created by 2 two placement new, you **cannot** use `f[1]` to get the second one. That's what the standard says. It is because `f` doesn't point to an actual array. – geza Jul 12 '18 at 04:58
  • @geza please see 7.6.1.1 `[...]The expression E1[E2] is identical (by definition) to *((E1)+(E2))[...]`. Placement new doesn't change that. The only case it would appear is if you tried to do placement new of an array insided the elements of the array (as an array of array) ; this is a consequence of 7.6.2.4/15 (where overhead x applies only to placement new of array). But the overall array stays the same - unfortunately, we could have implemented a realloc of arrays. – Michael Doubez Jul 12 '18 at 07:01
  • @MichaelDoubez: yes, but: http://eel.is/c++draft/expr.add#4. Pointer addition is defined only if the pointer points to an array. Some further thoughts: https://stackoverflow.com/questions/47498585/is-adding-to-a-char-pointer-ub-when-it-doesnt-actually-point-to-a-char-arr – geza Jul 12 '18 at 07:03
  • 1
    `new(f+i*2) double;` is undefined because the lifetime of the whole float array is finished when you create the first `double`. – xskxzr Jul 12 '18 at 07:53
  • @xskxzr: whoa, good catch :) I hopefully fixed it. – geza Jul 12 '18 at 07:56
  • @geza Sorry, I miss your point about 7.6.6/4. It only states that `If the expression P points to element x[i] of an array object` then it is UB to go outside the bounds of the array. It doesn't say that pointer arithmetic is limited to array. And the discussion you mention is the difference between struct member offsets vs array; this doesn't apply here. – Michael Doubez Jul 12 '18 at 08:15
  • @MichaelDoubez: the standard defines what happens, if `p` points to an array. If it doesn't point to an array, it is not defined at all. So I think it is UB. – geza Jul 12 '18 at 08:24
  • @geza 7.6.6/4 gives you the general rule `When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand.` This is not UB. – Michael Doubez Jul 12 '18 at 08:58

0 Answers0