如何使用shared_ptr或推荐另一种方法(unique_ptr)

How to use shared_ptr or recommend another approach (unique_ptr)

本文关键字:ptr 方法 另一种 unique 何使用 shared      更新时间:2023-10-16

UPD: 所以解决方案的要点:如果复制构造函数存在,它会阻止移动构造函数被std::move调用。问题解决了。
我尝试根据讲师的要求编写一个"线程安全堆栈":

  1. 它应该存储类型本身。
  2. 对于基元类型,它应该通过复制接收/返回(如 c 中的常见情况)
  3. 对于类类型,它不应该在接收/返回时调用冗余的复制构造函数。使用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("CONSTRUCTORn");
}
~SafeQueue() {
printf("DESTRUCTORn");
}
void push(T data) {
std::unique_lock<std::mutex> lock(_m);
_queue.push(data);
printf("Pushed %dn", 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(" nn//Wait for returned %d n", a);
if (!(_queue.empty())) {
outEl = _queue.front();
_queue.pop();
return true;
} else {
continue;
}
} else {
printf(" nn//Wait for returned %d n", a);
printf("Queue is emptyn");
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(" nn//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(" nn//Wait for returned %d n", a);
printf("Queue is emptyn");
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:%dn", z);
sq->push(numThread);
printf("even pushed:%dn", 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:%dn", z);
if(sq->pop_top(z))
printf("odd popped:%dn", z);

for(int i=0;i<2;i++) {
sq->push(i + numThread);
printf("odd pushed:%dn", i + numThread);
}
if(sq->pop_top(z))
printf("odd popped:%dn", z);
if(sq->pop_top(z))
printf("odd popped:%dn", 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:%dn", z->val);
sq->push(std::make_shared<myclass>(el));
printf("even pushed:%dn", 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:%dn", z->val);
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%dn", z->val);

for(int i=0;i<2;i++) {
sq->push(std::make_shared<myclass>(i + el.val));
printf("odd pushed:%dn", i + el.val);
}
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%dn", z->val);
z = std::move(sq->pop_top());
if(z)
printf("odd popped:%dn", 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还是什么?

删除不必要的构造函数和析构函数,并更改函数forEven_class和forOdd_class,您的代码将再次编译。
为什么要删除构造函数?因为编译器有规则如何生成默认构造函数。在您的情况下,您希望生成移动构造函数,但通过定义复制构造函数和析构函数,您阻止编译器这样做。您的选择是:

  • 正确定义所有构造函数,包括移动构造函数
  • 按照我的建议删除复制构造函数和析构函数,因为它们不做任何事情 execpt 首次亮相输出
  • 指示编译器生成默认的移动构造函数myclass(myclass &&obj) = default

请参阅有关自动生成移动操作的SO 如果你想要那些调试消息,那么你必须正确定义这些构造函数。包括他们必须执行的调试消息以外的任务。

关于函数forEven_class的变化,您不能通过引用来获取 myclass,因为它不是左值。有关此谷歌右值参考的更多信息。