我正在创建一个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]); });