It seems that std::byte
is generally meant to replace the use of char
in buffers for allocating blocks of raw memory.
But I'm worried about the fact that std::byte
can implicitly create objects in an array while char
cannot:
Consider this example of manually controlling memory allocation and lifetime of an int
object:
#include <stdlib.h>
#include <memory>
int main() {
//OPTION 1: allocate storage with an array of char
//(no objects are created; char cannot implicitly create objects in an array)
char* buffer = (char*)malloc(sizeof(int));
//OPTION 2: allocate storage with an array of std::byte
//(does std::byte implicitly create objects in the array here? it's capable of doing so)
//std::byte* buffer = (std::byte*)malloc(sizeof(int));
//explicitly create an int object, starting its lifetime:
int* ptr = ::new(buffer) int(11);
//explicitly destroy the int object, ending its lifetime:
std::destroy_at(ptr);
//deallocate storage (if this is an std::byte array, should you call their destructors first?):
free(buffer);
}
If you want to allocate raw memory so you can create objects in it (for example by using placement new), why would you want std::byte
to potentially fill the buffer with implicitly created objects beforehand?
Wouldn't it be better to use char
so you can avoid potential undefined behavior related to the lifetime of any implicitly created std::byte
objects (accessing them outside of their lifetimes by accident, forgetting to destroy them before de-allocating the memory, etc)?
I just want a block of raw memory where I can manually create & destroy objects, not a block of memory plus a bunch of implicit objects I never asked for that could silently introduce undefined behavior while I'm trying to use the block.
Thanks.
Wouldn't it be better to use
char
so you can avoid potential undefined behavior related to the lifetime of any implicitly createdstd::byte
objects
No. See [intro.object]/11
Some operations are described as implicitly creating objects within a specified region of storage. For each operation that is specified as implicitly creating objects, that operation implicitly creates and starts the lifetime of zero or more objects of implicit-lifetime types ([basic.types.general]) in its specified region of storage if doing so would result in the program having defined behavior. If no such set of objects would give the program defined behavior, the behavior of the program is undefined. If multiple such sets of objects would give the program defined behavior, it is unspecified which such set of objects is created.
[Note: ... ]
The abstract machine implicitly creates objects only if doing so would give the program defined behavior. So, if you choose to use a std::byte
array instead of a char
array, it makes it more likely, not less, that your program has defined behavior.
If you only ever attempt to access or refer to objects that you explicitly constructed into a std::byte
buffer, and never attempt to access or refer to any implicitly created objects, then it is not possible to get UB related to the lifetimes of those implicitly created objects, and they don't have any effect on the program's observable behavior.
However, your question is not actually about creating a char
array versus creating a std::byte
array; it's about calling malloc
. The standard specifies that malloc
implicitly creates objects in the buffer that it returns to you; whether you cast the void*
result to char*
, unsigned char*
, or std::byte*
doesn't take away malloc
's implicit object creation ability.