将来尝试引用已删除的函数

Posted

技术标签:

【中文标题】将来尝试引用已删除的函数【英文标题】:Attempting to Reference a Deleted Function in Future 【发布时间】:2016-04-19 05:31:52 【问题描述】:

我正在编写一个异步查找大量素数的程序。我通过使用TaskQueue 来实现,它本质上是一个由所有异步执行的期货组成的队列。涉及三个线程:将这些任务分配给TaskQueue 的主线程,检查期货是否有答案并决定是否存储数据的客户线程,以及启动和检查的主线程另外两个的状态。我在第 593 行收到错误:Error 2 error C2280: 'std::future<return_type>::future(const std::future<return_type> &)' : attempting to reference a deleted function e:\visualstudio\vc\include\xmemory0 593 1 MultiThreadTaskQueue 引用了文件 xmemory0,这似乎是由我 #included 的其他标头之一引用的文件。我的问题似乎是未来对象的复制构造函数的问题,可能是在复制之前被删除的对象,但我不确定在我的程序中会发生什么。这是我的代码的副本:

#include <iostream>
#include <queue>
#include <future>
#include <thread>
#include <vector>
#include <mutex>

using namespace std;
using longInt = long long unsigned int;

template <typename return_type>
class TaskQueue 
private:
    queue<future<return_type>> tasks;
    mutex mtx;

public:
    //return a copy of the queue
    queue<future<return_type>> copy() const 
        return tasks;
    


    //default constructor
    //does nothing, waits for input
    TaskQueue() 
        //do nothing
    

    //call constructors
    //adds task to queue
    template <typename ... Args, typename ... Ts>
    TaskQueue(return_type(*func)(Ts...), Args&& ... args) 
        tasks.push(std::async(func, args...));
    

    //copy constructor
    //copies another queue to this one
    TaskQueue(const TaskQueue<longInt> & in) 
        tasks = in.copy();
    

    //setter and getter functions

    //inserts a new task into the queue
    template <typename ... Args, typename ... Ts>
    void add(return_type(*func)(Ts...), Args&& ... args) 
        tasks.push(std::async(func, args...));
    

    //returns true if the task at the top of the queue is ready
    bool valid() 
        return tasks.front().valid();
    

    //gets the value, if the value is not ready, waits for it to be ready
    //pops the top task after getting it
    return_type get() 
        //mtx.lock();

        return_type temp = tasks.front().get();

        tasks.pop();

        //mtx.unlock();
        return temp;
    

    //waits for the value of the top of the queue to become ready
    void wait() 
        tasks.front().wait();
    

    //returns the number of tasks in the queue
    int size() const 
        return tasks.size();
    

;

bool HALT_ALL = false;
int MAX_TASKS_AT_ONCE = 10;

//prototypes
longInt isPrime(longInt);
void cook(TaskQueue<longInt>&);
void consumer(TaskQueue<longInt>&, vector<longInt> &);

int main() 

    //declare task queue and vector to store prime numbers
    TaskQueue<longInt> checkPrimes;
    vector<longInt> primes;
    primes.push_back(2);

    int maxPrimes;

    cout << "Enter max primes: ";
    cin >> maxPrimes;
    cout << endl;



    //launch the chef thread and the customer thread
    thread chef(&cook, checkPrimes);
    thread customer(&consumer, checkPrimes, primes);

    int previousSize = 0;

    //use main to keep track of the progress of the other threads
    while (primes.size() < maxPrimes) 
        if (previousSize != primes.size()) 
            cout << "Primes found: " << primes.size() << endl;
            previousSize = primes.size();
        
        else 
            checkPrimes.wait();
        
    

    //halt all other asynchronous operations
    HALT_ALL = true;

    //join other threads
    chef.join();
    customer.join();

    //print final prime found for verification of data
    cout << "Final Prime found: " << primes[primes.size() - 1] << endl;

    system("PAUSE");


    return 0;



//returns the number if it is prime or 0 if it is not
longInt isPrime(longInt n) 
    if (n <= 3) 
        if (n > 1) 
            return n;
        
        return 0;
    

    if (n % 2 == 0 || n % 3 == 0) 
        return 0;
    

    for (unsigned short i = 5; i * i <= n; i += 6) 
        if (n % i == 0 || n % (i + 2) == 0) 
            return 0;
        
    

    return n;


void cook(TaskQueue<longInt>& tasks) 
    longInt currentPrime = 3;

    while (!HALT_ALL) 
        if (tasks.size() < MAX_TASKS_AT_ONCE) 
            tasks.add(isPrime, currentPrime);
            currentPrime += 2;
        
    


void consumer(TaskQueue<longInt>& tasks, vector<longInt> & primes) 
    while (!HALT_ALL) 
        if (tasks.size() > 0) 
            longInt temp = tasks.get();

            if (temp > 0) 
                primes.push_back(temp);
            
        
    

【问题讨论】:

【参考方案1】:

您正试图在此处复制std::futures:

queue<future<return_type>> copy() const 
    return tasks;

std::future 是不可复制的,它的复制构造函数已被删除(参见例如here),因此您会收到该编译器错误消息。

删除copy() 函数和TaskQueue 复制构造函数。

其实你的错误就在这里:

thread chef(&cook, checkPrimes);
thread customer(&consumer, checkPrimes, primes);

std::thread 构造函数如果参数是右值则移动其参数,否则复制它们。所以只需传递reference_wrappers 即可:

thread chef(&cook, std::ref(checkPrimes));
thread customer(&consumer, std::ref(checkPrimes), std::ref(primes));

它不仅会让你的代码编译,它也会让它在语义上更正确,因为你可能不希望每个线程都有自己的任务队列和素数向量。

请注意,您必须进行适当的同步以避免数据争用。

【讨论】:

那么就是删除那个函数那么简单吗? @Stephen 如果您不需要它 - 那么是的,就是这么简单。我相信你也必须禁止复制你的TaskQueue 我删除了复制构造函数和函数复制,因为它们是我唯一会使用它的地方。但错误仍然存​​在。 @Stephen 你不只是“删除”复制构造函数,你把它变成= delete,然后编译器会显示你复制TaskQueue的所有地方,你必须消除所有此类错误。 我用 TaskQueue(const TaskQueue &amp; in) = delete; 替换了我的复制构造函数,但编译器只是给出了与上面相同的错误消息。

以上是关于将来尝试引用已删除的函数的主要内容,如果未能解决你的问题,请参考以下文章

std::mutex 引起的 C2280 尝试引用已删除的函数

将 QMutex 添加到类后“尝试引用已删除的函数”

调用递归函数时出现编译器错误 - “试图引用已删除的函数”

VS2019 C++ 错误 C2280 试图引用已删除的函数 inl

查找引用了已删除函数的位置

从向量 C++ 中删除对象试图引用已删除的函数