提问人:G Stepanovic 提问时间:4/22/2023 最后编辑:G Stepanovic 更新时间:4/23/2023 访问量:165
使用静态函数初始化静态 const std::array 会删除 const(使其可写)
Initializing static const std::array with a static function removes const (makes it writable)
问:
我有一个包含私有成员的类(结构)。我希望这个成员是静态和恒定的(不可写的)。看起来好像通过静态函数添加初始化,破坏了成员数组的恒定性。
我本来希望编译器在我尝试写入定义为 const 的数组时会抱怨。相反,当我运行时,我得到:static const std::array
- 使用列表初始值设定项时的 SEGFAULT,
- 使用上述功能时能够写入
类还通过返回 std::array 迭代器来提供迭代器。当我通过初始化器列表(在结构声明之外)初始化 std::array 时,然后尝试通过迭代器修改数组中的元素时,我得到了 SEGFAULT,尽管编译器没有抱怨(有点意料之中且很好)。
但是,当我通过另一个函数初始化数组时(在下面的代码中,我能够更改元素值,这是不行的。
值得一提的是,下面的代码只是为了重现这个问题。我真的需要以一种非平凡的方式初始化更大大小的静态常量数组的能力 - 即使用一些三角函数。
我不明白为什么会这样。任何帮助或指导都表示赞赏。谢谢。static std::array<int, 4> HalfCircleStatic_init();
我试过这个:
#include <iostream>
#include <array>
struct ArrayContainer
{
using iterator = typename std::array<int, 4>::iterator ;
inline constexpr iterator begin() { return iterator(&arr[0]); }
inline constexpr iterator end() { return iterator(&arr[0] + arr.size()); }
private:
static const std::array<int, 4> arr;
static std::array<int, 4> HalfCircleStatic_init();
};
const std::array<int, 4> ArrayContainer::arr = {1,2,3,4};
std::array<int, 4> ArrayContainer::HalfCircleStatic_init() {
std::array<int, 4> retVal{};
for (int i = 0; i < 4; ++i) retVal[i] = i+1;
return retVal;
}
int main() {
ArrayContainer arrCont;
auto it = arrCont.begin();
std::cout << "Value at 0: " << *it << std::endl;
*it = 5;
std::cout << "Value at 0: " << *it << std::endl;
return 0;
}
生产:
Value at 0: 1
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
如果我将初始值设定项(定义)更改为:
const std::array<int, 4> ArrayContainer::arr = ArrayContainer::HalfCircleStatic_init();
我明白了:
Value at 0: 1
Value at 0: 5
Process finished with exit code 0
在 Ubuntu 上使用 GCC 8.4
答:
你可以这样编码:
{
// In your class
static constexpr std::array<int, 4> HalfCircleStatic_init();
}
constexpr std::array<int, 4> ArrayContainer::HalfCircleStatic_init() {
std::array<int, 4> retVal{};
for (int i = 0; i < 4; ++i) retVal[i] = i+1;
return retVal;
}
触发 SEGFAULT 的原因是您正在写入程序的只读会话,并且只读属性是在运行时之前确定的。通过直接提供数字,它们通常由程序中的编译器硬编码,即您的二进制程序直接包含 ,当程序加载时,它们将作系统放在只读页面上;但是通过使用函数,在没有优化的情况下,初始化实际上是一个运行时的事情,所以编译器必须把你的数组放到一个可写的会话中(否则初始化本身会触发SEGFAULT,对吧?上面的代码所做的只是将运行时的东西移动到编译时间(by ),以便编译器尝试计算它,然后可以在二进制程序中对其进行硬编码。如果你想强制编译器这样做,并在失败时报告错误,可以这样做。1, 2, 3, 4
const
constexpr
consteval
但是,对于浮点数组,编译器无法在编译时计算它们。保留是通过编译器保护只读数据的最可靠方法,您不应依赖 SEGFAULT 进行调试。例如,您可以返回类似 的东西,以在运行之前而不是运行后终止写入行为。const
cbegin()
评论
> inline constexpr iterator begin() { return iterator(&arr[0]); } inline
> constexpr iterator end() { return iterator(&arr[0] + arr.size()); }
上面可能是一个指标,应该可以返回 arr.begin() 和 arr.end()
尝试const_iterator而不是迭代器 (或者将数组成员设置为非常量 -- 如果您希望在构造后能够修改它)
评论
begin(arr)
end(arr)
using iterator = decltype(begin(arr));
好的,似乎这可能有效(在某种程度上)。使用 lambda 初始化成员数组:static const
const std::array<int, 4> ArrayContainer::arr = {
[] {
std::array<int, 4> retVal{};
for (int i = 0; i < 4; ++i) retVal[i] = i + 1;
return retVal;
}() };
这是一致的,因为当我尝试写作时,它会产生段错误。
评论
arr
.long 1
上一个:cpp 类声明中类常量的定义
下一个:C++ 对局部静态变量的依赖
评论
&arr[0]
iterator(&arr[0])
*it = 5
iterator(&arr[0])
iterator{&arr[0]}