The Question of a Lifetime
-
We all should know, QByteArray::fromRawData is to be used with care, pre and hindsight.
But I don't know enough about constexpr to judge if the lifetime of this char data is guaranteed under all circumstances:
void Class::onFunction() noexcept { constexpr char serialNumberCommand[] = "\x11\x01\x1E\xD0"; emit writeRawData(QByteArray::fromRawData(serialNumberCommand, sizeof(serialNumberCommand))); }
Anyone with answers and/or opinions is welcome :D
-
@J-Hilk
I would say "no", though it might work. I would refer you to e.g. https://stackoverflow.com/a/13867690/489865The short answer is that not only is static useful, it is pretty well always going to be desired.
First, note that static and constexpr are completely independent of each other. static defines the object's lifetime during execution; constexpr specifies that the object should be available during compilation. Compilation and execution are disjoint and discontiguous, both in time and space. So once the program is compiled, constexpr is no longer relevant.
Every variable declared constexpr is implicitly const but const and static are almost orthogonal (except for the interaction with static const integers.)
constexpr
is only a compile-time thing. You can't be sure what code is generated. You need to guarantee the lifetime ofchar serialNumberCommand[]
. As it standsserialNumberCommand[]
may only be a local variable which gets initialised each time and destroyed at end of function. It is thestatic
you need for persistence. At which point theconstexpr
isn't relevant since the compiler does not need to know the value of that string. Sostatic constexpr
if you want, butstatic
alone should be equally good. -
@JonB said in The Question of a Lifetime:
you're right, static is probably the way I should go.
But I dislike
static
and wanted to explore new fancy ways!!! :D -
It might work right now, but will not in the future.
There is a new feature coming to C++26 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2795r3.html) which addresses a problem related to this. Currently if you do something like this
void f() { const char password[] = "secret"; } void g() { char str[7]; std::cout << str << '\n'; } int main() { f(); g(); }
it will most likely print
secret
. Both functions will use the same stack space and reuse the same memory. The proposal for C++26 is to handle uninitialized variables explicitly to avoid this problem.On the other hand this also means in your concrete case if some other function reuses the same stack space it will overwrite
\x11\x01\x1E\xD0
.Someone should check the following with the standard, but I believe there is a difference between
char serialNumberCommand[] = "\x11\x01\x1E\xD0";
and
char *serialNumberCommand = "\x11\x01\x1E\xD0";
I would expect the first version to copy the string into the serialNumberCommand array. In the latter case you are just holding a pointer to an existing string in static storage. This pointer can then be handed safely to
QByteArray::fromRawData
asQByteArray
will not hold the pointer handed to it, but the thing it points to. The thing it points to should be permanent. (I am not sure it the C++ standard guarantees this, but it is the general implementation of C strings.)If you want something more fancy, there is not only
constexpr
but alsoconstinit
(since C++20). cppreference (https://en.cppreference.com/w/cpp/language/constinit) mentions thatconstinit
declares a variable with static or thread storage duration. However, as the example on that page shows, you need to writestatic constinit
inside a function. Justconstinit
alone will not do. -
@SimonSchroeder
Your description above is in substance, correct. I had to check it to make sure myself. ;^) By assigning the string literal to an array (const or not) it is considered "auto class". When you create a pointer to the string literal the pointer will "typically" point to a RO-data segment containing the literal.