> if(mem.readCustomType<double>(start) == d_Y + playerHeight)
The first problem is going to be comparing doubles for equality.
If you're off by even a single bit in the LSB, then "damn close" just becomes "nope, not it".
Even if they are bit-equal in memory, you might still need 
-ffloat-store
 
The following options control compiler behavior regarding floating point arithmetic. These options trade off between speed and correctness. All must be specifically enabled. 
-ffloat-store 
    Do not store floating point variables in registers, and inhibit other options that might change whether a floating point value is taken from a register or memory. 
 
    This option prevents undesirable excess precision on machines such as the 68000 where the floating registers (of the 68881) keep more precision than a "double" is supposed to have. Similarly for the x86 architecture. For most programs, the excess precision does only good, but a few programs rely on the precise definition of IEEE floating point. Use -ffloat-store for such programs, after modifying them to store all pertinent intermediate computations into variables.  | 
> for(start; start <= end; start++)
doubles are not scattered at random addresses in memory.  Each type has a minimum alignment.
So perhaps
for(start; start <= end; start += alignof(double))
You should also have < end, not <= end.
A caveat to that would be various attempts to obfuscate the code to make simple memory searches less effective (such as structure packing).  But this always comes with a performance cost in the software.
Speaking of which, you might want to benchmark
mem.readCustomType<double>(0xD57AAE00)
against
mem.readCustomType<double>(0xD57AAE01)
A naive pointer cast would just get you a 
https://en.wikipedia.org/wiki/Bus_error on most architectures.  This should mean your unaligned access is doing a lot more work than the aligned case.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
 
  | 
#include <iostream>
#include <iomanip>
struct foo {
  char c;
  double d;
};
#pragma pack(push,1)
struct bar {
  char c;
  double d; // trying to be sneaky by hiding double in an odd place
};
#pragma pack(pop)
void show(const double f) {
  std::cout << std::fixed << std::setprecision(15) << f
            << " = " << std::hexfloat << f
            << std::endl;
}
int main() {
  double a = 1.7999999523163;
  double b = 73 + a;
  double c = 74.7999999523163;
  show(a);
  show(b);
  show(c);
  std::cout << "Double alignment=" << alignof(double) << std::endl;
  std::cout << sizeof(foo) << std::endl;
  std::cout << sizeof(bar) << std::endl;
}
$ g++ -std=c++11 foo.cpp
$ ./a.out 
1.799999952316300 = 0x1.cccccc0000047p+0
74.799999952316298 = 0x1.2b33333000001p+6
74.799999952316298 = 0x1.2b33333000001p+6
Double alignment=8
16
9
  |  |