结构中的常量成员即使在初始化后也返回0

时间:2019-06-07 19:48:41

标签: c++

我正在创建一个struct来保存有关我的项目需要的纹理的数据。该结构有五个成员: 纹理图集宽度(一行中的纹理量), 纹理图集高度(一列中的纹理量), 纹理单位宽度(图谱宽度的倒数), 纹理单位高度(图集高度的倒数) 和一个无符号的GLint存储纹理ID。

但是,即使在构造函数中初始化了这些成员之后,由于Atlas宽度和高度都设置为0,因此我在程序后面还会收到ArithmeticException

我已经尝试重新排列代码并尝试其他看似随机的更改,但是没有一个起作用。

设置项目(或至少相关部分)的方式是,我拥有TextureData结构的标头和源文件。我在名为“ GeneralData.h”的标头中创建此类型的常量对象。我没有与此标头关联的源文件,因此所有实现也都包含在其中。

这是TextureData代码:

// TextureData.h
struct TextureData
{
    const int ATLAS_WIDTH;
    const int ATLAS_HEIGHT;
    const float TEXTURE_UNIT_WIDTH;
    const float TEXTURE_UNIT_HEIGHT;

    GLuint TEXTURE_ID;

    TextureData(int, int);

    virtual ~TextureData() {}
};

// TextureData.cpp
#ifndef STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include <../stb_image.h>
#endif // STB_IMAGE_IMPLEMENTATION

TextureData::TextureData(int atlas_width, int atlas_height):
    ATLAS_WIDTH(atlas_width),
    ATLAS_HEIGHT(atlas_height),
    TEXTURE_UNIT_WIDTH(1.0f / ATLAS_WIDTH),
    TEXTURE_UNIT_HEIGHT(1.0f / ATLAS_HEIGHT)
{
    glGenTextures(1, &TEXTURE_ID);
    glBindTexture(GL_TEXTURE_2D, TEXTURE_ID);

    int width;
    int height;

    unsigned char* pixels = stbi_load("res/block_textures.png", &width, &height, nullptr, 4);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

这是GeneralData标头的相关部分:

const TextureData BLOCK_TEXTURE(8, 8);

// These functions are called at some point with index = 0.
// Their behaviour should not be undefined
inline float tex_coord_x(int index)
{
    return index % BLOCK_TEXTURE.ATLAS_WIDTH * BLOCK_TEXTURE.TEXTURE_UNIT_WIDTH;
}

inline float tex_coord_y(int index)
{
    return index / BLOCK_TEXTURE.ATLAS_HEIGHT * BLOCK_TEXTURE.TEXTURE_UNIT_HEIGHT;
}

如上所述,我得到一个运行时异常(算术),因为我被零除。在这种情况下,我应除以(或模数)八(在TEXTURE_UNIT_WIDTH情况下,应除以0.125f)。

这是调用函数的地方。这是在函数定义和BLOCK_TEXTURE定义之下。

//编辑:

template <typename T, size_t SIZE, typename FUNCTION>
inline std::array<T, SIZE> make_array (FUNCTION func)
{
    std::array<T, SIZE> arr;
    unsigned int index = 0;
    std::for_each(arr.begin(), arr.end(), [&func, &index, &arr](const T& val){ arr[index] = func(index); index++; });

    return arr;
}

const std::array<float, B_LAST * 6> TEXTURE_COORDS = make_array<float, B_LAST * 6>([](unsigned int index){ return index%2 == 0? tex_coord_x(TEXTURE_INDICES[index / 2]) : tex_coord_y(TEXTURE_INDICES[index / 2 + 1]); });

2 个答案:

答案 0 :(得分:2)

嗯。

此代码在清理并将其放入单个文件后可以正常工作。问题的主要提示是您自己的语句“这是GeneralData标头的相关部分”。您将const值放入标头中,并多次包含它。 const值默认情况下具有内部链接(为什么?不知道...),这意味着您可以获得BLOCK_TEXTURE变量的多个版本。您的代码可能使用了错误的代码,而调试器却捕获了另一种代码。在BLOCK_TEXTURE的构造函数中比较指向此对象的指针,并在当前引发异常以确保确定。作为解决方案,添加extern关键字将BLOCK_TEXTURE的定义转换为声明:

extern const TextureData BLOCK_TEXTURE;

并将其定义在单个文件中的某个位置:

const TextureData BLOCK_TEXTURE(8, 8);

请注意,这可能会在某些时候为您带来静态初始化失败。因此,我建议改用静态函数(在标题中):

static inline GET_BLOCK_TEXTURE() {
    static const TextureData BLOCK_TEXTURE(8, 8);
    return BLOCK_TEXTURE;
}

这将确保您首次使用时已初始化BLOCK_TEXTURE。

答案 1 :(得分:1)

我相信您的代码中有静态init惨败(但是我不确定100%,这是C ++的某些非常奇怪的部分,并且是UBs)

您可以在头文件中定义全局变量。您在注释中提到不能删除 <DataGridTemplateColumn Width="Auto" Header="Is Locked"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <materialDesign:PackIcon x:Name="LockIcon" Kind="LockOpenOutline" Foreground="Green"/> <DataTemplate.Triggers> <DataTrigger Binding="{Binding isLocked}" Value="True"> <Setter Property="Kind" Value="Lock" TargetName="LockIcon"/> <Setter Property="Foreground" Value="Red" TargetName="LockIcon"/> </DataTrigger> </DataTemplate.Triggers> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> 关键字,因为您会遇到多个定义错误,这是事实。 但是您在每个翻译单元中也有多个全局变量定义。

每个包含inline的文件都有其自己的GeneralData.h定义,因此一个文件可能会访问另一个文件中的变量。并且可能尚未初始化。

通过检查在BLOCK_TEXTURE开始之前还是之后发生异常,可以“确认”(与确认UB一样多)静态初始化失败。使用调试器并检查回溯发生的时间,或者仅在main的第一行中打印一些内容。

解决方案非常简单:您只应在一个文件中定义全局变量。

main中:

GeneralData.h

extern const TextureData BLOCK_TEXTURE; extern const std::array<float, B_LAST * 6> TEXTURE_COORDS ; 中:

GeneralData.cpp
相关问题