Excluir o ponteiro às vezes resulta em corrupção de heap

Eu tenho um aplicativo multithreaded que é executado usando uma classe de pool de threads personalizada. Todos os threads executam a mesma função, com diferentes parâmetros.

Esses parâmetros são fornecidos para a classe do conjunto de encadeamentos da seguinte maneira:

// jobParams is a struct of int, double, etc...
jobParams* params = new jobParams;
params.value1 = 2;
params.value2 = 3;

int jobId = 0;

threadPool.addJob(jobId, params);

Assim que um thread não tem nada para fazer, ele obtém os próximos parâmetros e executa a função job. Eu decidi cuidar da exclusão dos parâmetros na classe threadpool:

ThreadPool::~ThreadPool() {
    for (int i = 0; i < this->jobs.size(); ++i) {
        delete this->jobs[i].params;
    }
}

No entanto, ao fazer isso, às vezes recebo um erro de corrupção de heap:

Endereço inválido especificado para RtlFreeHeap

O estranho é que, em um caso, funciona perfeitamente, mas em outro programa ele falha com esse erro. Eu tentei apagar o ponteiro em outros lugares: no segmento após a execução da função de trabalho (eu recebo o mesmo erro de corrupção de heap) ou no final da função de trabalho em si (nenhum erro neste caso).

Eu não entendo como apagar os mesmos ponteiros (eu verifiquei, os endereços são os mesmos) de lugares diferentes muda alguma coisa. Isso tem alguma coisa a ver com o fato de ser multithread?

Eu tenho uma seção crítica que lida com o acesso aos parâmetros. Eu não acho que o problema é sobre o acesso sincronizado. De qualquer forma, o destruidor é chamado apenas uma vez que todos os threads são feitos, e eu não apago nenhum ponteiro em nenhum outro lugar. O ponteiro pode ser excluído automaticamente?

Quanto ao meu código. A lista de jobs é uma fila de uma estrutura, composta pelo id de um job (usado para obter posteriormente a saída de um job específico) e os parâmetros.

getNextJob() é chamado pelos encadeamentos (eles têm um ponteiro para o ThreadPool) toda vez que terminam de executar seu último trabalho.

void ThreadPool::addJob(int jobId, void* params) {
    jobData job; // jobData is a simple struct { int, void* }
    job.ID = jobId;
    job.params = params;

    // insert parameters in the list
    this->jobs.push(job);
}

jobData* ThreadPool::getNextJob() {    
    // get the data of the next job
    jobData* job = NULL;

    // we don't want to start a same job twice,
    // so we make sure that we are only one at a time in this part
    WaitForSingleObject(this->mutex, INFINITE);

    if (!this->jobs.empty())
    {
        job = &(this->jobs.front());
        this->jobs.pop();
    }

    // we're done with the exclusive part !
    ReleaseMutex(this->mutex);

    return job;
}

questionAnswers(7)

yourAnswerToTheQuestion