c++ - 即使在释放指针后,Valgrind 仍显示 Leak_DefinitelyLost

标签 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中的相关push函数是

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

最佳答案

您显示的程序不会删除分配的Taskpush 将所有权从 task 移开,因此 tp 始终为 null。

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


一些质量问题:

  • 正如评论中所指出的,通过非常量引用传递唯一指针通常是一种糟糕的设计。当您打算转让所有权时按值(value)传递。

    I've deleted the copy constructor on Task. Would passing by value still work?

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

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

关于c++ - 即使在释放指针后,Valgrind 仍显示 Leak_DefinitelyLost,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55003606/

相关文章:

c++ - 我可以要求编译器禁止定义模板类成员函数的泛型版本吗?

C#线程同步

c# - 查询队列和线程安全

c++ - boost::scoped_lock 解锁

c# - GDI+ DrawImage 在 C++ (Win32) 中比在 C# (WinForms) 中慢得多

c++ - boost c++ 中的纪元时间到日期/时间格式

c - 指向结构体的指针,这还是指向结构体的指针吗?

c++ - std::vector、std::move 和指针失效

c - 对链表进行排序时出现段错误

java - 使用双重检查惯用语重置延迟加载的字段