即使释放指针,Valgrind也会显示Leak_DefinitelyLost

时间:2019-03-05 13:08:25

标签: c++ pointers thread-safety unique-ptr

在一些名为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;
    }
}

并且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 个答案:

答案 0 :(得分:2)

您显示的程序没有delete分配的Taskpush将所有权从task移开,因此tp始终为空。

资源所有权已转移到queue_中,并且示例程序中未显示该指针如何泄漏(假设valgrind是正确的)。


一些质量问题:

  • 正如注释中指出的那样,通过非const引用传递唯一指针通常是一个糟糕的设计。当您打算转让所有权时,按值传递。

      

    我已删除Task上的副本构造函数。按价值传递仍然有效吗?

    Task是否可复制与唯一指针是否可以按值传递无关。唯一指针是可移动的,与指向对象的类型无关,因此可以按值传递。

  • 不要为了删除内存而从唯一指针释放。只需让唯一指针超出范围即可-它的析构函数负责删除。

答案 1 :(得分:0)

由于所有权已不再是您的所有权,因此您无法删除该原始任务。

autoStartup=true

阻止队列:

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));
    }
}

如果您想避免std :: move的麻烦,请改用shared_ptr