Valgrind показывает Leak_DefiniteLost даже после освобождения указателя - PullRequest
0 голосов
/ 05 марта 2019

В каком-то файле с именем Tasks.h у меня есть следующая функция: -

void source_thread_func(BlockingQueue<Task> &bq, int num_ints)
{
std::cout<<"On source thread func"<<std::endl; // Debug
    for (int i = 1; i <= num_ints; i++)
    {
        //Valgrind does not like this
        std::unique_ptr<Task> task(new Task(i, i == num_ints));
    std::cout<<"Pushing value = "<<i<<std::endl; // Debug
        bq.push(task);
        Task* tp = task.release();
        assert (task.get() == nullptr);
        delete tp;
    }
}

и соответствующая функция push в BlockingQueue равна

    void push(std::unique_ptr<T>& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push(std::move(item));
        mlock.unlock();
        cond_.notify_one();
    }

Но это все равно вызывает утечку при проверке с Valgrind. Не могли бы вы сказать мне, где утечка? Я прилагаю скриншот результата Valgrind. Как еще я могу удалить этот указатель? enter image description here

Редактировать: Задача не содержит конструктора копирования (я его удалил)

Дальнейшее редактирование: полный пример

//Tasks.h
namespace threadsx
{
class Task
{
public:
    Task(int val, bool sentinel = false)
    {
        m_val = val;
        Sent = sentinel;
    }

    int m_val;
    int Sent;

    //disable copying
    Task (const Task&) = delete;
};


void source_thread_func(BlockingQueue<Task> &bq, int num_ints)
{
std::cout<<"On source thread func"<<std::endl; // Debug
    for (int i = 1; i <= num_ints; i++)
    {

        std::unique_ptr<Task> task(new Task(i, i == num_ints));
        std::cout<<"Pushing value = "<<i<<std::endl; // Debug
        bq.push(task);
        Task* tp = task.release();
        assert (task.get() == nullptr);
        delete tp;
    }
}
}

+++++++++++++++++++++++++++++++

///BlockingQueue.h
namespace threadsx
{
 // -- Custom Blocking Q
template <typename T>
class BlockingQueue
{
private:
    std::queue<std::unique_ptr<T>> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;

    void push(std::unique_ptr<T>& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push(std::move(item));
        mlock.unlock();
        cond_.notify_one();
    }

    BlockingQueue()=default;
    BlockingQueue(const BlockingQueue&) = delete;            // disable copying
    BlockingQueue& operator=(const BlockingQueue&) = delete; // disable assignment

};
}

+++++++++++++++++++++++++++++++

//main.cpp
int main(int argc, char **argv)
{

int num_ints = 30;
int threshold = 5;

threadsx::BlockingQueue<threadsx::Task> q;
std::vector<int> t;

std::thread source_thread(threadsx::source_thread_func, std::ref(q), num_ints);

if(source_thread.joinable())
    source_thread.join();

return 0;
}

Ответы [ 2 ]

2 голосов
/ 05 марта 2019

Программа, которую вы показываете, не delete Task, который был выделен.push перемещает владение от task, поэтому tp всегда равно нулю.

Владение ресурсом переносится в queue_, и как этот указатель просочился (при условии, что valgrind верен)в примере программы не показано.


Несколько проблем с качеством:

  • Как отмечается в комментариях, обычно плохой дизайн для передачи уникальных указателейпо неконстантной ссылке.Передайте по значению, когда вы намереваетесь передать право собственности.

    Я удалил конструктор копирования в Задаче.Будет ли передача по значению все еще работать?

    Возможность копирования Task не имеет значения, может ли уникальный указатель передаваться по значению.Уникальный указатель может перемещаться независимо от типа указанного объекта и поэтому может передаваться по значению.

  • Не освобождайте от уникального указателя только для того, чтобы удалить память.Просто отпустите уникальный указатель из области видимости - его деструктор позаботится об удалении.

0 голосов
/ 05 марта 2019

Вам не разрешено удалять необработанное задание, поскольку право собственности больше не принадлежит вам.

void source_thread_func(BlockingQueue<Task>& bq, int num_ints)
{
    std::cout<<"On source thread func"<<std::endl; // Debug
    for (int i = 1; i <= num_ints; i++)
    {
        std::unique_ptr<Task> task = std::make_unique<Task>(i, i == num_ints);
        bq.push(std::move(task));
    }
}

Очередь блокировки:

#include <memory>
#include <mutex>
#include <condition_variable>
#include <deque>

template <typename T>
class BlockingQueue {
public:
    void push(std::unique_ptr<T>&& item)
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        queue_.push_back(std::move(item));
        cond_.notify_one();
    }

    std::unique_ptr<T> pop()
    {
        std::unique_lock<std::mutex> mlock(mutex_);
        if (queue_.empty()) {
            cond_.wait(mlock, [this] { return !queue_.empty(); });
        }
        std::unique_ptr<T> ret = std::unique_ptr<T>(queue_.front().release());
        queue_.pop_front();
        return ret;
    }

private:
    std::deque<std::unique_ptr<T>> queue_;
    std::mutex mutex_;
    std::condition_variable cond_;
};

Если вы хотите избавиться от головной боли std :: move, используйте взамен shared_ptr

...