gcc 使用静态函数初始化静态const std::array将删除const(使其可写)

vulvrdjw  于 2023-04-30  发布在  其他
关注(0)|答案(3)|浏览(137)

我有一个包含static const std::array私有成员的类(struct)。我希望这个成员是静态的和常量(不可写)。看起来好像通过静态函数添加初始化,破坏了成员数组的稳定性。当我尝试写入定义为const的数组时,我希望编译器会抱怨。相反,当我跑步时,我得到:

  1. SEGFault使用列表初始化器时,
    1.使用上述功能时的写入能力
    类也通过返回std::array迭代器提供迭代器。当我通过初始化器列表初始化std::array(在struct声明之外),然后尝试通过迭代器修改数组中的元素时,我得到SEGFAULT,尽管编译器没有抱怨(有点预期和罚款)。然而,当我通过另一个函数初始化数组时(在下面的代码static std::array<int, 4> HalfCircleStatic_init();中,我能够更改元素值,这是不正确的。值得一提的是,下面的代码只是为了重现这个问题。我真的需要能够以一种非平凡的方式初始化更大大小的静态常量数组。e.使用一些三角函数。我不明白为什么会这样。任何帮助或指导都很感激。谢谢。
    我试过这个:
#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)

如果我将initializer(definition)修改为:
const std::array<int, 4> ArrayContainer::arr = ArrayContainer::HalfCircleStatic_init();
我得到了这个:

Value at 0: 1
Value at 0: 5

Process finished with exit code 0

使用GCC 8.4在Ubuntu上

wfveoks0

wfveoks01#

> inline constexpr iterator begin() { return iterator(&arr[0]); } inline
> constexpr iterator end()   { return iterator(&arr[0] + arr.size()); }

上面可能是一个指示器,它应该可以返回arr。开始()和arr。end()
尝试const_iterator而不是iterator(或者使数组成员非const--如果您希望能够在构造之后修改它的话)

smdnsysy

smdnsysy2#

你可以这样写代码:

{
    // 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会被触发的原因是你写的是程序的只读会话,而只读属性是在运行前确定的。通过直接提供数字,它们通常被编译器硬编码在程序中,即。e.你的二进制程序直接包含1, 2, 3, 4,当程序加载时,它们会被OS放到只读页面上;但是通过使用函数,当没有优化时,初始化实际上是运行时的事情,所以编译器必须将const数组放入可写会话(否则初始化本身将触发SEGFAULT,对吗?上面的代码所做的只是将运行时的东西移动到编译时(通过constexpr),以便编译器将尝试计算它,然后可能将其硬编码在二进制程序中。如果你想强制编译器这样做,并在失败时报告错误,consteval可以这样做。
然而,对于浮点数组,编译器不能在编译时计算它们。保持const是通过编译器保护只读数据的最好方法,并且不应该依赖SEGFault来调试。例如,您可以返回一个类似cbegin()的东西,以在运行之前而不是运行之后终止写入行为。

dojqjjoe

dojqjjoe3#

这可能是工作(在某种程度上)。使用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;

        }() };

这是一致的,因为当我尝试写入时它会产生segfault。

相关问题