我有一个整数向量,想要随机访问其中一个元素。这是一个最小的例子:
#include <iostream>
#include <random>
#include <vector>
class Random
{
private:
const int N = 8;
std::vector<int> data;
std::mt19937 randomGenerator;
public:
void Reset(int seed = 0) {
data.resize(N + 1);
if(seed) { this->randomGenerator.seed(seed); }
}
void UpdateVector(int delta) {
std::uniform_int_distribution<int> uniformBuffer(1, N);
/*unsigned*/ int randomIndex = uniformBuffer( randomGenerator );
data[randomIndex] += delta;
}
};
int main() {
Random rnd;
rnd.Reset();
rnd.UpdateVector(1);
return 0;
}
这在Microsoft Visual C ++ 2017中的调试模式下完美运行。但是当我在发布模式下运行程序时,它会因访问冲突而崩溃。快速查看生成的汇编代码会显示一些神奇的事情,其中int
索引被扩展(带有符号)到size_t
,然后是一个奇怪的值(我认为它是{{1} })被添加 - 这确实不再是一个有效的索引!
我设法通过取消注释未签名的&#39;来修复错误。 0xffff0004
声明中的修饰语,但我很好奇为什么。这是我使用的编译器中的一个错误(快速搜索没有发现任何可能的错误)或者我是否存在误解?
答案 0 :(得分:2)
在昨天调查您之前的question时,它已关闭并且您在此处重新发布之前将其删除,问题是Microsoft优化器对64位代码的错误。
从uniform_int_distribution<int>
获取结果并将其作为size_t
值传递给向量operator[]
时,内部用于“将有符号范围转换为无符号范围,反之亦然”的调整因子为保留在分发类之外,并为数组访问进行缩放,从而导致出现问题。奇怪的是,将结果转换为size_t
进行显示时不会发生这种情况。
此示例演示了此问题。
#include <vector>
#include <random>
#include <iostream>
#include <iomanip>
const int N = 8;
std::mt19937 randomGenerator;
class tester {
public:
int operator[](size_t idx) const {
std::cout << "Offset is " << std::hex << idx << "\n";
return int(idx);
}
};
int main() {
std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8};
std::uniform_int_distribution<int> uniformBuffer(1, N);
std::cout << "Number " << size_t(uniformBuffer(randomGenerator)) << "\n";
tester t;
std::cout << "Index " << v[t[uniformBuffer(randomGenerator)]] << "\n";
}
使用64位编译器,使用cl /W4 /MD /EHsc /Ox
编译输出
Number 5
Offset is ffffffff00000007
Index 7
使用v
是必要的。如果省略,则传递给tester
的偏移量为7。