There are several efficiency savings possible in your code. The most efficient method (apart from using a pre-calculated look-up table for small (<1000) n) is the sieve of Erastosthenes. 
A very naive version of this algorithm (see also the answer by 
coderredoc)
std::vector<int> primes(int n)
{
    std::vector<bool> is_prime(n+1,true);
    for(auto divisor=2; divisor*divisor <= n; ++divisor)
        for(auto candidate=divisor*divisor; candidate <= n; candidate+=divisor)
            is_prime[candidate]=false;
    std::vector<int> result;
    for(auto candidate=2; candidate <= n; ++candidate)
        if(is_prime[candidate]) result.push_back(candidate);
    return result;
}
essentially reverses the loops over candidates and divisors compared to your original algorithm, but only tests for divisors satisfying divisor*divisor<=candidate.
This algorithm can be substantially improved by realizing that we only need to test for prime divisors (which is the main trick of the sieve)
std::vector<int> primes(int n)
{
    std::vector<bool> is_prime(n+1,true);
    for(auto divisor=2; divisor*divisor <= n; ++divisor)
        if(is_prime[divisor])
            for(auto candidate=divisor*divisor; candidate <= n; candidate+=divisor)
                is_prime[candidate]=false;
    std::vector<int> result;
    for(auto candidate=2; candidate <= n; ++candidate)
        if(is_prime[candidate]) result.push_back(candidate);
    return result;
}
which cuts down on the testing for large n. A further efficiency saving (by a factor ~2 in space and time) is possible by avoiding even candidates and divisors:
std::vector<int> primes(int n)
{
    if(n<2) return {};
    if(n==2) return {2};
    std::vector<bool> is_prime((n+1)>>1,true);
    for(auto divisor=3; divisor*divisor <= n; divisor+=2)
        if(is_prime[divisor>>1])
            for(auto candidate=divisor*divisor; candidate <= n; candidate+=2*divisor)
                is_prime[candidate>>1]=false;
    std::vector<int> result(1,2);
    for(auto candidate=3; candidate <= n; candidate+=2)
        if(is_prime[candidate>>1]) result.push_back(candidate);
    return result;
}
This algorithm has a poor memory access pattern (into the is_prime[]), which becomes a problem for very large n. A more sophisticated method, segmented sieve, can avoid that, see the above link.