未定义的行为,以阵列/矢量结束地址?

问题描述:

我想编写一个模板函数,可以使用std::vector将数据传递给C风格的API(在我的使用案例中,特别是OpenGL)。该代码我想出了这个样子的:未定义的行为,以阵列/矢量结束地址?

template<typename T> 
void pass_data(GLuint buffer, std::vector<T> const& data) { 
    glBindBuffer(GL_ARRAY_BUFFER, buffer); 
    glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(T), data.data(), GL_STATIC_DRAW); 
} 

这似乎是一个简单的解决方案,直到它发生,我认为T可能会导致&t[1] - &t[0] != sizeof(T)是正确对齐限制,这将意味着这个函数会不准确地通过整个阵列。所以我重写功能做到这一点,而不是:

template<typename T> 
void pass_data(GLuint buffer, std::vector<T> const& data) { 
    glBindBuffer(GL_ARRAY_BUFFER, buffer); 
    glBufferData(GL_ARRAY_BUFFER, static_cast<size_t>(&data[data.size()] - &data[0]), data.data(), GL_STATIC_DRAW); 
} 

但是,目前还不清楚,我认为这样的一个得票最多的高端访问是安全的(我敢肯定,这是不确定的行为)。确保我的函数准确评估向量的字节大小并将正确的参数传递给基础C-API调用的最佳方法是什么?

注意:我不想讨论关于如何使用OpenGL [误]的问题。我只关注精确模拟矢量的指针+大小的愿望。

+0

我怀疑你会被允许创建一个这样的矢量。它保证连续的存储。那么你能给出一个实际用例的例子吗?我并不是说这是不可能的,但是你不得不原谅我认为这有点令人担忧。 – StoryTeller

+2

'&t [1] - &t [0]!= sizeof(T)'在什么情况下这是真实的?你的'T'跨越过程边界? – PnotNP

+1

减去两个指针不会给你以字节为单位的大小,它给出你已经知道是'data.size()'的元素的大小。你的第二个例子*不等于第一个例子。 –

是的,data[data.size()]是未定义的行为。

幸运的是,你不需要任何这样的事情,因为(char*)&data[1] - (char*)&data[0] == sizeof(T)实际上是保证任何类型T。所以回到data.size() * sizeof(T)

但我也想补充一个

static_assert(std::is_trivially_copyable<T>::value, "Invalid type"); 

是有点更安全。