As far as i can say Position::set assumes the object is blank and does not clear the existing values in it, which leads to wrong move generation if the object is reused:
int main() {
initialise_all_databases();
zobrist::initialise_zobrist_keys();
Position p;
Position::set("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - ", p);
auto n = perft<WHITE>(p, 4);
std::cout<<n<<std::endl;
Position::set("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", p);
Position::set("8/2p5/3p4/KP5r/1R3p1k/8/4P1P1/8 w - - ", p); //same as first position
n = perft<WHITE>(p, 4); //same as the first perft call
std::cout << n << std::endl; //this gives wrong perft count
return 0;
}