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

但是,即使在构造函数中初始化了这些成员之后,由于 map 集的宽度和高度都设置为0,所以我稍后在程序中仍会收到ArithmeticException

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

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

这是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 header 的相关部分:
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]); });

最佳答案

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

您在头文件中定义一个全局变量。您在注释中提到无法删除inline关键字,因为您会遇到多个定义错误,这是事实。 但在每个翻译单元中,全局变量也有多个定义。

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

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

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

GeneralData.h中:

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

GeneralData.cpp中:
const TextureData BLOCK_TEXTURE(8, 8);
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]); });

10-08 11:40