Klang complains: "the pointer is initialized with a temporary array"

I have an array of (pointers to) arrays of different lengths that I recognized, I could determine using compound literals:

const uint8_t *const minutes[] = { (const uint8_t[]) {END}, (const uint8_t[]) {1, 2, 3, 4, 5 END}, (const uint8_t[]) {8, 9, END}, (const uint8_t[]) {10, 11, 12, END}, ... }; 

gcc accepts this just fine, but clang says: pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression . What does it mean? The code seems to work, but again, it seems that many things work when they point to memory that is no longer allocated. Is this something I should worry about? (Ultimately, I really need it to work with gcc.)

Update . Something fishy is happening. He says here that:

Component literals give lvalues. This means that you can take the address of a complex literal, which is the address of an unnamed object declared by a composite literal. As long as the composite literal is not of type const, you can use a pointer to change it.

  `struct POINT *p; p = &(struct POINT) {1, 1}; 

This code example seems to do exactly what I'm trying to do: a pointer to something defined by a complex literal. Is the clang error message legal? Will this point to unallocated memory when compiling with clang or gcc?

Update 2 : Found some documentation : β€œIn C, a composite literal denotes an unnamed object with a static or automatic storage time. In C ++, a composite literal denotes a temporary object that survives to the end of its full expression.” Thus, it seems that clang is right to warn about this, and gcc probably should, but does not, even with -Wall -Wextra .

I cannot guess why the useful C function was removed from C ++, and there was no elegant alternative way to do the same.

+5
source share
3 answers

Well, clang is right, and this should be done as follows:

 namespace elements { const uint8_t row1[] = {END}; const uint8_t row2[] = {1, 2, 3, 4, 5, END}; ... } const uint8_t *const minutes[] = { elements::row1, elements::row2, ... }; 

You can come up with more solutions in C ++, for example using std::tuple :

 #include <tuple> constexpr auto minutes = std::make_tuple( std::make_tuple(), std::make_tuple(1,2,3,4,5), std::make_tuple(8,9,10)); #include <iostream> #include <type_traits> int main() { std::cout << std::tuple_size<decltype(minutes)>::value << std::endl; std::cout << std::tuple_size<std::remove_reference_t<decltype(std::get<1>(minutes))>>::value << std::endl; } 
+3
source

update: thanks to deniss for indicating a flaw in the original solution.

 static constexpr uint8_t END = 0xff; template<uint8_t...x> const uint8_t* make() { static const uint8_t _[] = { x..., END }; return _; } const uint8_t* const array[] = { make<>(), make<1, 2, 3, 4, 5>(), make<8, 9>(), make<10, 11, 12>() }; 
+2
source

Well, that means this expression

 (const uint8_t[]) {1, 2, 3, 4, 5 END}, 

creates a temporary object - temporarily, because it does not have a name that can go beyond the expression of which the part is a part; which collapses at the end of the full expression, which means the following:

  }; 

defines a "full expression", after which all temporary objects will be destroyed, and the minutes pointer array contains pointers pointing to the destroyed objects, so the compiler gives a warning.

Hope this helps.

+1
source

All Articles