Prime Sieve and brute force
When you find a prime number, say 7, you begin crossing out all odd multiples of 7 from the primeCandidates vector.  You do this by incrementing index += loop, where loop is the prime number, and but primeCandidates only holds odd candidates, so the step size in natural numbers would be 2*loop.

The issue is you start by removing 7 from primeCandidates, then 21, then 35.  At this point in the sieve, you've already eliminated multiples of 3 and 5, so marking off 3*7=21 and 5*7=35 is just busy work.  And marking off 1*7=7 is just pointless.  What you should be doing is starting to eliminate at 7*7=49.  It saves only three eliminations during the 7 loop, but the saving get more substantial as the prime gets larger.  For instance, when you get to 199, you wouldn't eliminate 1*199, 3*199, 5*199, 7*199, ... 191*199, 193*199, 195*199, 197*199.  You would just start at 199*199 and go up from there.

Code change:

// Now strain out all factors of the prime we just found, starting with prime^2
index = loop * loop / 2




std::vector&lt;std::size_t&gt; is overkill for primeCandidates.  You only ever store 1 or 0, so allocating 4 or 8 bytes for each candidate is wasting memory.

std::vector&lt;char&gt; would reduce the memory load to 1 byte per candidate.

std::bitset&lt;N&gt; will reduce this to 1 bit per candidate.  Alternately, the vector specialization std::vector&lt;bool&gt; will also give 1 bit per candidate, with a non-compile-time fixed number of bits.