9

I want to dynamically allocate known size of memory (just memory, not bothering about type) and fill it with exactly the same amount of data but any type (I'm only sure it will be primitive type). Ofc later I'm going to free it.

Is it ok? :

auto dest = new int8_t[n];
std::memcpy(dest, src, n);
delete[] dest;

src is ptr to an array of size n (Bytes). I've ofc chosen int8_t becuase it's the clearest way to allocate certain amount of memory. In fact the code above isn't exaclt what it will be. delete[] will be called on pointer of type which actually it points to. So for example if src was an array of floats (forget about last line of above code):

float * ptr = dest;
delete[] ptr;

So again. Will it be ok?

Criss
  • 581
  • 5
  • 17
  • Why don't u test it with valgrind? – ItayB Sep 23 '16 at 19:56
  • You have allocated an array of n int8_t. So the number of bytes allocated is not n. – Anon Mail Sep 23 '16 at 20:00
  • 4
    Why doing it like this? Don't you know the type of elements in `src`? – Jean-Baptiste Yunès Sep 23 '16 at 20:04
  • from my point of view this will work (I would probably use uint8_t) but I am curious if its UB – pm100 Sep 23 '16 at 20:06
  • 1
    @AnonMail `std::int8_t` is [*exactly* one octet (eight bits)](http://en.cppreference.com/w/cpp/types/integer). So i'm pressed to see how your assertion an array of `n` items of type `int8_t` is not equivalent to `n` bytes. – WhozCraig Sep 23 '16 at 20:07
  • 1
    This will work if you are just using primitive types -- `operator new[]` and `operator delete[]` take a `void*` as the argument. – rlbond Sep 23 '16 at 20:14
  • Sounds like you want `std::optional`/`boost::optional`? Or really any class that placement-news objects into raw memory, such as `std::vector` or `std::variant`/`boost::variant`. – GManNickG Sep 23 '16 at 20:16
  • It's going to be part of copy ctor of class wrapping GL buffer. It has to copy the data but implicitly create new GL buffer (glGenBuffers). So type is not known. You declare it in glVertexAttribPointer function by GL_INT, GL_FLOAT etc... – Criss Sep 23 '16 at 23:10
  • I'm trying to avoid templates.. – Criss Sep 23 '16 at 23:19
  • 2
    @Criss why? ... :^) character limit – RamblingMad Sep 24 '16 at 01:43
  • Uhm in fact template is not a good solution. Buffer should be able to store sny primitive type. Even when at first it was floats, later you could decide to put there some ints. (Actually it doesnt store data but just wraps some GL buffer calls and "sends" data to graphic card by glBufferData func). According to @Nikita, what im talking about in the question is safe. I'll ty it. – Criss Sep 24 '16 at 09:53

4 Answers4

6

It is ok, but only if you use a char array or an unsigned char array, because of the special alignment guarantees for these types:

5.3.4 New
11 When a new-expression calls an allocation function and that allocation has not been extended, the new- expression passes the amount of space requested to the allocation function as the first argument of type std::size_t. That argument shall be no less than the size of the object being created; it may be greater than the size of the object being created only if the object is an array. For arrays of char and unsigned char, the difference between the result of the new-expression and the address returned by the allocation function shall be an integral multiple of the strictest fundamental alignment requirement (3.11) of any object type whose size is no greater than the size of the array being created. [ Note: Because allocation functions are assumed to return pointers to storage that is appropriately aligned for objects of any type with fundamental alignment, this constraint on array allocation overhead permits the common idiom of allocating character arrays into which objects of other types will later be placed. — end note ]

emphasis by me.

Another requirement is that you only use primitive types or PODs, because you don't call a constructor, but the (trivial) destructor (through delete).

alain
  • 11,939
  • 2
  • 31
  • 51
3

According to the specification of the new expression execution of new int8_t[n] calls operator new[](sizeof(int8_t)*n + overhead).

Important note about overhead:

Many implementations use the array overhead to store the number of objects in the array which is used by the delete[] expression to call the correct number of destructors.

In its turn, operator new[](std::size_t count) returns the void* pointer to the allocated memory block. This pointer further should be used in delete [] expression.

You have simple types with no destructors, so delete[] only need to deallocate memory block. It can do it safely with both int8_t* dest or float* ptr.

UPDATE: It's better to change array type from int8_t to char or unsigned char. For arrays with such types C++ standard garantees that you will get the proper aligment for further data placement. Thanks @alain. More details together with standard quote can be found in his answer.

Nikita
  • 6,270
  • 2
  • 24
  • 37
  • There is no guarantee that an array of `uint8_t` is properly aligned for the new type. – alain Sep 24 '16 at 12:05
  • @alain `int8_t` is 1 byte value, it's [alignment requirement](http://en.cppreference.com/w/cpp/language/object) is 1, same as for `char`, `signed char`, and `unsigned char`. I don't see any problem with it. By the way, on many systems `int8_t` defined as `typedef signed char int8_t;`. – Nikita Sep 24 '16 at 13:18
  • No, for `char` and `unsigned char` arrays, there are special alignment guarantees that may or may not apply for `int8_t` arrays. (See the standard quote in my answer) – alain Sep 24 '16 at 14:00
  • @alain Thnx, I've got this point and updated my answer accordingly. – Nikita Sep 24 '16 at 14:55
2

Maybe will be better to use the std vector? No need to manually free memory..

std::vector<uint8_t> vdest(n);
uint8_t * dest = vdest.data();

std::memcpy(dest, src, n);

float * ptr = reinterpret_cast<float*>(dest);
...

EDIT: As @alain pointed out: "There is no guarantee that an array of uint8_t is properly aligned for the new type"

So if you want use this approach It will be a good idea to look this question: Is it good practice to use std::vector as a simple buffer?

Community
  • 1
  • 1
pavnik
  • 466
  • 2
  • 7
  • But the question is that array of int8_t was allocated but in the allocated memory will be other types (e.g. float) and then will deallocate (delete[]) be safe? – Criss Sep 23 '16 at 23:23
  • 2
    There is no guarantee that an array of `uint8_t` is properly aligned for the new type. – alain Sep 24 '16 at 12:05
0

I understand this is common scenario in Real Time programming. To make sure that each structure is aligned to uint8_t/unsigned char(any custom defined Byte size datatype), make sure each of you structure (apart from primitive data Structure) use the concept #pragma pack.

Nitisha
  • 11
  • 2