将来尝试引用已删除的函数
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,这似乎是由我 #include
d 的其他标头之一引用的文件。我的问题似乎是未来对象的复制构造函数的问题,可能是在复制之前被删除的对象,但我不确定在我的程序中会发生什么。这是我的代码的副本:
#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::future
s:
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_wrapper
s 即可:
thread chef(&cook, std::ref(checkPrimes));
thread customer(&consumer, std::ref(checkPrimes), std::ref(primes));
它不仅会让你的代码编译,它也会让它在语义上更正确,因为你可能不希望每个线程都有自己的任务队列和素数向量。
请注意,您必须进行适当的同步以避免数据争用。
【讨论】:
那么就是删除那个函数那么简单吗? @Stephen 如果您不需要它 - 那么是的,就是这么简单。我相信你也必须禁止复制你的TaskQueue
。
我删除了复制构造函数和函数复制,因为它们是我唯一会使用它的地方。但错误仍然存在。
@Stephen 你不只是“删除”复制构造函数,你把它变成= delete
,然后编译器会显示你复制TaskQueue的所有地方,你必须消除所有此类错误。
我用 TaskQueue(const TaskQueue & in) = delete;
替换了我的复制构造函数,但编译器只是给出了与上面相同的错误消息。以上是关于将来尝试引用已删除的函数的主要内容,如果未能解决你的问题,请参考以下文章
std::mutex 引起的 C2280 尝试引用已删除的函数