我有一组(指向)不同长度的数组,我学会了我可以使用复合文字来定义:
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说:pointer is initialized by a temporary array, which will be destroyed at the end of the full-expression
。这是什么意思?代码似乎正在工作,但是当它们指向不再分配的内存时,很多事情似乎似乎。这是我需要担心的吗? (最终我只需要它与gcc一起工作。)
更新:有些事可疑。它说here:
复合文字产生左值。这意味着您可以获取复合文字的地址,该复合文字是复合文字声明的未命名对象的地址。只要复合文字没有const限定类型,就可以使用指针来修改它。
`struct POINT *p; p = &(struct POINT) {1, 1};
这个示例代码似乎正在完成我正在尝试做的事情:指向由复合文字定义的内容的指针。 clang错误消息合法吗?当用clang或gcc编译时,这最终会指向未分配的内存吗?
更新2 :
找到一些documentation:"在C中,复合文字指定具有静态或自动存储持续时间的未命名对象。 在C ++中,复合文字指定一个临时对象,它只能存在于其完整表达式的结尾。"所以似乎clang是正确的警告这一点,gcc可能也应该如此,但即使-Wall -Wextra
也没有。
我无法猜测为什么从C ++中删除了有用的C功能,并且没有提供完成相同功能的优雅替代方法。
答案 0 :(得分:3)
嗯,铿锵是对的,这应该这样做:
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;
}
答案 1 :(得分:2)
更新:感谢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>()
};
答案 2 :(得分:1)
嗯,这意味着,这个表达
(const uint8_t[]) {1, 2, 3, 4, 5 END},
创建一个临时对象 - 临时对象,因为它没有任何名称可以超出它所属的表达式 - 它在完整表达式的末尾被销毁,这意味着:
};
定义“完整表达式”,此时所有临时对象都将被销毁,指针数组minutes
保存指向销毁的指针对象,这就是编译器发出警告的原因。
希望有所帮助。