UPD: 所以解决方案的要点是:如果存在复制构造函数,它会阻止std::move
调用移动构造函数。问题解决了。
我已经尝试根据讲师的要求编写“线程安全堆栈”:
shared_ptr
来实现此目标。我不能让3号工作。
更具体一点:我不知道如何将shared_ptr传递给这样设计的类。而且我几乎可以肯定我已经在语法上错误地编写了类。
#ifndef SAFE_QUEUE
#define SAFE_QUEUE
#include <condition_variable>
#include <thread>
#include <stdlib.h>
#include <queue>
#include <mutex>
#include <chrono>
template<typename T>
class SafeQueue {
public:
SafeQueue() {
printf("CONSTRUCTOR\n");
}
~SafeQueue() {
printf("DESTRUCTOR\n");
}
void push(T data) {
std::unique_lock<std::mutex> lock(_m);
_queue.push(data);
printf("Pushed %d\n", data);
_cv.notify_one();
}
void push(std::shared_ptr<T> data) {
std::unique_lock<std::mutex> lock(_m);
_queue.push(*data);
_cv.notify_one();
}
bool pop_top(T &outEl) {
std::unique_lock<std::mutex> lock(_m);
while (1) {
bool a;
if (a = this->_cv.wait_for(lock, std::chrono::milliseconds(1000),
[this]() -> bool { return !(this->_queue.empty()); })) {
printf(" \n\n//Wait for returned %d \n", a);
if (!(_queue.empty())) {
outEl = _queue.front();
_queue.pop();
return true;
} else {
continue;
}
} else {
printf(" \n\n//Wait for returned %d \n", a);
printf("Queue is empty\n");
return false;
}
}
}
std::shared_ptr<T> pop_top() {
std::unique_lock<std::mutex> lock(_m);
while (1) {
bool a;
if (a = this->_cv.wait_for(lock, std::chrono::milliseconds(1000),
[this]() -> bool { return !(this->_queue.empty()); })) {
printf(" \n\n//Wait for returned %d \n", a);
if (!(_queue.empty())) {
std::shared_ptr<T> cur = std::make_shared<T>(_queue.front());
_queue.pop();
return cur;
} else {
continue;
}
} else {
printf(" \n\n//Wait for returned %d \n", a);
printf("Queue is empty\n");
return nullptr;
}
}
}
private:
std::queue<T> _queue;
std::condition_variable _cv;
std::mutex _m;
};
#endif
主:
#include <iostream>
#include "safeQueue.h"
#include <vector>
void forEven(SafeQueue<int> *sq, int numThread){
// for(int i=0;i<3;i++)
// sq->push(i+numThread);
// sq->push(1);
// for(int i=0;i<2;i++)
//sq->push(numThread);
int z;
if(sq->pop_top(z))
printf("even popped:%d\n", z);
sq->push(numThread);
printf("even pushed:%d\n", numThread);
}
class myclass{
public:
int val;
myclass(myclass &obj){
printf("copy constructor");
}
myclass(int val):val(val){
printf("constructor");
}
~myclass(){
printf("destructor");
}
};
void forOdd(SafeQueue<int> *sq, int numThread){
int z;
if(sq->pop_top(z))
printf("odd popped:%d\n", z);
if(sq->pop_top(z))
printf("odd popped:%d\n", z);
for(int i=0;i<2;i++) {
sq->push(i + numThread);
printf("odd pushed:%d\n", i + numThread);
}
if(sq->pop_top(z))
printf("odd popped:%d\n", z);
if(sq->pop_top(z))
printf("odd popped:%d\n", z);
}
void forEven_class(SafeQueue<myclass> *sq, myclass &el){
// for(int i=0;i<3;i++)
// sq->push(i+numThread);
// sq->push(1);
// for(int i=0;i<2;i++)
//sq->push(numThread);
std::shared_ptr<myclass> z = std::move(sq->pop_top());
if(z)
printf("even popped:%d\n", z->val);
sq->push(std::make_shared<myclass>(el));
printf("even pushed:%d\n", el.val);
}
void forOdd_class(SafeQueue<myclass> *sq, myclass &el){
std::shared_ptr<myclass> z = std::move(sq->pop_top());
if(z)
printf("odd popped:%d\n", z->val);
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%d\n", z->val);
for(int i=0;i<2;i++) {
sq->push(std::make_shared<myclass>(i + el.val));
printf("odd pushed:%d\n", i + el.val);
}
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%d\n", z->val);
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%d\n", z->val);
}
int main(){
SafeQueue<int> sq;
SafeQueue<myclass> sq_c;
std::vector<std::thread> v_t;
for(int i=0;i<5;i++){
if( i%2 )
v_t.push_back(move(std::thread(forOdd,&sq,i+1)));
else
v_t.push_back(move(std::thread(forEven,&sq,i+1)));
}
for(int i=0;i<5;i++){
v_t[i].join();
}
std::cout << "class test" <<std::endl;
for(int i=0;i<5;i++){
if( i%2 )
v_t.push_back(move(std::thread(forOdd_class,&sq_c,std::move(myclass(i+1)))));
else
v_t.push_back(move(std::thread(forEven_class,&sq_c,std::move(myclass(i+1)))));
}
for(int i=0;i<5;i++){
v_t[i].join();
}
// std::thread t1(forThreads,&sq,1);
// std::thread t2(forThreads,&sq,2);
// std::thread t3(forThreads,&sq,2);
//
// t1.join();
// t2.join();
// t3.join();
return 0;
}
由于极端错误,我无法使forEven_class()和forOdd_class()工作:
如果我只留下forEven / Odd_class函数的未注释定义,我得到:
error: no matching function for call to ‘myclass::myclass(const myclass&)’
所以似乎共享ptr尝试调用复制构造函数
如果我取消注释,我会得到整体:
In file included from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/mutex:42:0,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/condition_variable:39,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/safeQueue.h:9,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:2:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional: In instantiation of ‘struct std::_Bind_simple<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>’:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:116:86: required from here
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1665:61: error: no type named ‘type’ in ‘class std::result_of<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>’
typedef typename result_of<_Callable(_Args...)>::type result_type;
^
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1695:9: error: no type named ‘type’ in ‘class std::result_of<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>’
_M_invoke(_Index_tuple<_Indices...>)
^
In file included from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/mutex:38:0,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/condition_variable:39,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/safeQueue.h:9,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:2:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple: In instantiation of ‘struct std::_Head_base<2ul, myclass, false>’:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:231:12: recursively required from ‘struct std::_Tuple_impl<1ul, SafeQueue<myclass>*, myclass>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:231:12: required from ‘struct std::_Tuple_impl<0ul, void (*)(SafeQueue<myclass>*, myclass&), SafeQueue<myclass>*, myclass>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:390:11: required from ‘class std::tuple<void (*)(SafeQueue<myclass>*, myclass&), SafeQueue<myclass>*, myclass>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1703:39: required from ‘struct std::_Bind_simple<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:116:86: required from here
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:137:17: error: ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const std::_Head_base<_Idx, _Head, false>&) [with long unsigned int _Idx = 2ul; _Head = myclass]’ declared to take const reference, but implicit declaration would take non-const
constexpr _Head_base(const _Head_base&) = default;
^
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple: In instantiation of ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(_UHead&&) [with _UHead = myclass; long unsigned int _Idx = 2ul; _Head = myclass]’:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:273:42: required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&&) [with long unsigned int _Idx = 2ul; _Head = myclass; _Tail = {}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:900:43: required by substitution of ‘template<class _Tp, class _Arg, class> static std::true_type std::__do_is_direct_constructible_impl::__test(int) [with _Tp = std::_Tuple_impl<2ul, myclass>; _Arg = std::_Tuple_impl<2ul, myclass>&&; <template-parameter-1-3> = <missing>]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:912:43: required from ‘struct std::__is_direct_constructible_impl<std::_Tuple_impl<2ul, myclass>, std::_Tuple_impl<2ul, myclass>&&>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:134:12: required from ‘struct std::__and_<std::is_destructible<std::_Tuple_impl<2ul, myclass> >, std::__is_direct_constructible_impl<std::_Tuple_impl<2ul, myclass>, std::_Tuple_impl<2ul, myclass>&&> >’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:916:12: required from ‘struct std::__is_direct_constructible_new_safe<std::_Tuple_impl<2ul, myclass>, std::_Tuple_impl<2ul, myclass>&&>’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:994:12: [ skipping 21 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:1175:12: required from ‘struct std::is_nothrow_move_constructible<std::_Tuple_impl<1ul, SafeQueue<myclass>*, myclass> >’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/type_traits:134:12: required from ‘struct std::__and_<std::is_nothrow_move_constructible<void (*)(SafeQueue<myclass>*, myclass&)>, std::is_nothrow_move_constructible<std::_Tuple_impl<1ul, SafeQueue<myclass>*, myclass> > >’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:269:7: required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>&&) [with long unsigned int _Idx = 0ul; _Head = void (*)(SafeQueue<myclass>*, myclass&); _Tail = {SafeQueue<myclass>*, myclass}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1727:41: required from ‘typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type std::__bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}; typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type = std::_Bind_simple<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:116:86: required from here
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:142:42: error: no matching function for call to ‘myclass::myclass(myclass)’
: _M_head_impl(std::forward<_UHead>(__h)) { }
^
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:142:42: note: candidates are:
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: myclass::myclass(int)
myclass(int val):val(val){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: no known conversion for argument 1 from ‘myclass’ to ‘int’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: myclass::myclass(myclass&)
myclass(myclass &obj){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: no known conversion for argument 1 from ‘myclass’ to ‘myclass&’
In file included from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/mutex:38:0,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/condition_variable:39,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/safeQueue.h:9,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:2:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple: In instantiation of ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(const _Head&) [with long unsigned int _Idx = 2ul; _Head = myclass]’:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:257:44: recursively required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const _Head&, const _Tail& ...) [with long unsigned int _Idx = 1ul; _Head = SafeQueue<myclass>*; _Tail = {myclass}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:257:44: required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(const _Head&, const _Tail& ...) [with long unsigned int _Idx = 0ul; _Head = void (*)(SafeQueue<myclass>*, myclass&); _Tail = {SafeQueue<myclass>*, myclass}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:400:33: required from ‘constexpr std::tuple< <template-parameter-1-1> >::tuple(const _Elements& ...) [with _Elements = {void (*)(SafeQueue<myclass>*, myclass&), SafeQueue<myclass>*, myclass}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1678:74: required from ‘std::_Bind_simple<_Callable(_Args ...)>::_Bind_simple(_Callable&&, _Args2&& ...) [with _Args2 = {SafeQueue<myclass>*, myclass}; <template-parameter-2-2> = void; _Callable = void (*)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/functional:1727:41: required from ‘typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type std::__bind_simple(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}; typename std::_Bind_simple_helper<_Func, _BoundArgs>::__type = std::_Bind_simple<void (*(SafeQueue<myclass>*, myclass))(SafeQueue<myclass>*, myclass&)>]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/thread:137:47: required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(SafeQueue<myclass>*, myclass&); _Args = {SafeQueue<myclass>*, myclass}]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:116:86: required from here
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:135:25: error: no matching function for call to ‘myclass::myclass(const myclass&)’
: _M_head_impl(__h) { }
^
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/tuple:135:25: note: candidates are:
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: myclass::myclass(int)
myclass(int val):val(val){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: no known conversion for argument 1 from ‘const myclass’ to ‘int’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: myclass::myclass(myclass&)
myclass(myclass &obj){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: no known conversion for argument 1 from ‘const myclass’ to ‘myclass&’
In file included from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/x86_64-redhat-linux/bits/c++allocator.h:33:0,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/allocator.h:46,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/string:41,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/locale_classes.h:40,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/ios_base.h:41,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/ios:42,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/ostream:38,
from /opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/iostream:39,
from /gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:1:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/ext/new_allocator.h: In instantiation of ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = myclass; _Args = {const myclass&}; _Tp = myclass]’:
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/stl_deque.h:1403:6: required from ‘void std::deque<_Tp, _Alloc>::push_back(const value_type&) [with _Tp = myclass; _Alloc = std::allocator<myclass>; std::deque<_Tp, _Alloc>::value_type = myclass]’
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/bits/stl_queue.h:216:9: required from ‘void std::queue<_Tp, _Sequence>::push(const value_type&) [with _Tp = myclass; _Sequence = std::deque<myclass, std::allocator<myclass> >; std::queue<_Tp, _Sequence>::value_type = myclass]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/safeQueue.h:37:9: required from ‘void SafeQueue<T>::push(std::shared_ptr<_Tp1>) [with T = myclass]’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:69:43: required from here
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/ext/new_allocator.h:120:4: error: no matching function for call to ‘myclass::myclass(const myclass&)’
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
^
/opt/rh/devtoolset-3/root/usr/include/c++/4.9.2/ext/new_allocator.h:120:4: note: candidates are:
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: myclass::myclass(int)
myclass(int val):val(val){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:32:5: note: no known conversion for argument 1 from ‘const myclass’ to ‘int’
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: myclass::myclass(myclass&)
myclass(myclass &obj){
^
/gpfs/home/ichernovalov/Sharamet/Threads 1 2 5 6/5 safeQueue/main.cpp:29:5: note: no known conversion for argument 1 from ‘const myclass’ to ‘myclass&’
所以我根本不知道如何使用shared_ptr。 (特别是将它传递给线程) 我可能会让讲师弄错了。那么你建议使用什么:unque_ptr或什么?
答案 0 :(得分:1)
删除不必要的构造函数和析构函数,并更改forEven_class和forOdd_class的函数,代码将compile again。
为什么删除构造函数?因为编译器有规则如何生成默认构造函数。在您的情况下,您希望生成移动构造函数,但通过定义复制构造函数和析构函数,您可以阻止编译器执行此操作。您的选择是:
myclass(myclass &&obj) = default
在automatic generation of move operations上查看此消息 我想要那些调试消息,然后你必须正确定义那些构造函数。包括除调试消息以外的其他任务。
关于函数forEven_class的更改,您不能通过引用获取myclass,因为它不是左值。有关此google rvalue参考的详细信息。