C++ 铿锵抱怨道:“这是一个很好的例子。”;指针由临时数组“初始化”;

C++ 铿锵抱怨道:“这是一个很好的例子。”;指针由临时数组“初始化”;,c++,clang,allocation,C++,Clang,Allocation,我有一个不同长度的数组(指向数组的指针),我知道我可以使用复合文字来定义它: 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很好地接受了这一点,但c

我有一个不同长度的数组(指向数组的指针),我知道我可以使用复合文字来定义它:

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很好地接受了这一点,但clang说:
指针是由一个临时数组初始化的,它将在完整表达式的末尾被销毁。这是什么意思?代码似乎在工作,但是,当它们指向不再分配的内存时,很多事情似乎都在工作。这是我需要担心的事吗?(最终,我只需要与gcc一起使用它。)

更新:有些可疑的事情正在发生。它说:

复合文本产生左值。这意味着您可以获取复合文字的地址,它是由复合文字声明的未命名对象的地址。只要复合文字没有const限定类型,就可以使用指针修改它

   `struct POINT *p;
   p = &(struct POINT) {1, 1};
这个示例代码似乎正是我想要做的:一个指向由复合文字定义的东西的指针。那么,叮当声错误消息是否合法?当使用clang或gcc编译时,这是否会指向未分配的内存

更新2: 发现一些:“在C中,复合文字指定一个没有名字的对象,它具有静态或自动存储持续时间。在C++中,复合文字指定一个临时对象,它只在其完整表达式结束时才生存。”看来,CLAN是正确的警告,GCC可能也应该这样做,但不是。即使使用
-Wall-Wextra


我猜不出为什么C++中有一个有用的C特征被删除,没有一个优美的替代方法来完成同样的事情。

< P>这意味着,这个表达式

(const uint8_t[]) {1, 2, 3, 4, 5 END},
创建一个临时对象-临时的,因为它没有任何名称可以超过它所属的表达式-在完整表达式结束时被销毁,这意味着:

 };
定义“完整表达式”,此时所有临时对象都将被销毁,指针数组
minutes
包含指向已销毁对象的指针,这就是编译器发出警告的原因


希望有帮助。

更新:感谢deniss指出原始解决方案中的缺陷

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>()
};
静态constexpr uint8\u t END=0xff;
模板
const uint8_t*make()
{
静态常数uint8_t_[]={x..,END};
返回;;
}
常量uint8_t*常量数组[]={
make(),
make(),
make(),
make()
};

嗯,叮当声是对的,应该这样做:

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,
    ...
}; 

你可以考虑更多的C++解决方案,比如使用<代码> 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;
}
#包括
constexpr auto minutes=std::make_tuple(
std::make_tuple(),
标准::组合(1,2,3,4,5),
std::make_tuple(8,9,10));
#包括
#包括
int main(){

std::在使用gcc时,您是否使用
-W
标志进行编译?如果您不使用它,它可能会出现。-Wall-Wextra,这显然是同一件事。您是否尝试删除不必要的
(const uint8\u t[])
在每一行的开头?@richardhoges这不是不必要的。这是复合文字的语法。没有它,编译器希望看到类似指针的东西,而在花括号中看到一些东西,并抱怨:
错误:C中“const uint8_t*const”类型的标量初始值设定项周围有大括号,这在f是合法的ILE范围,在块范围内不合法。请在下面显示问题的范围。在C++中,复合文字是不允许的。是的,我怀疑。我该怎么办?):首先把它们定义为数组。或者更好地重新设计它。试试使用<代码> STD::数组< /C>。你能举个例子吗?必须有一个D的方式。o这不需要创建几十个单独命名的变量,我实际上不想或不打算使用这些变量…对吗?这个复合文本方法是我从这里的答案中得到的,所以-它真的错了吗?(这是针对一个具有30k程序存储和2k ram的嵌入式系统,因此我需要代码尽可能小、高效、简单,并且通常在我的控制下。我试图避免任何像std::array这样的“花哨”的东西。)你能将
(const uint8_t[]){1、2、3、4、5 END}
定义为数组吗?比如
const uint8_t a0[]={1,2,3,4,5结束}
等等。然后将它们用作
分钟数的元素。这会进行编译,尽管它会使编译后的应用程序更大,并且占用更多的内存—这对嵌入式系统来说并不理想。知道为什么吗?我也不确定它在做什么—据我所知,一旦在c和c之间持续存在,静态变量应该分配空间该函数每次调用时是如何分配新空间的?它会为不同的数字行生成一个静态函数。每个静态函数将包含一个静态数组(和一个隐藏的互斥体)。当你说内存更多时,我们说的是多少?经过优化后,几百字节可能是值得的,以便于维护。注意:对于相同数量的参数,此函数只生成1个数组(填充了第一次调用的值)。是的。这是真的。这是我的疏忽。@mattmcnabhah!yay!:-)我在这些函子和lambda中使用
,因为我似乎很容易将其解释为“it”或“相关的东西”。为什么我不喜欢你的第一个选项:它很混乱。它很容易拼写错误,如果我对行重新排序或稍后添加行,则必须进行大量的变量重命名,或者只是保留行号RSS无序化。说起来,它似乎是最直接的方法来获得数据的内存表示。我将要查看您的第二个选项,用STD::TUPLE和CONTXPROP。我比C++更舒服的C++(如果您还没有猜到),但是我使用一些C++库来处理这个PR。