问题描述
为什么编译器会抱怨将线程函数的声明更改为 void thr(std :: shared_ptr< Base>& p)
.Complie错误:
Why the compiler complains if the the thread function delaration is changed to void thr(std::shared_ptr<Base>& p)
.Complie error:
136 |类型名称朽烂< _Args> ::类型...> ::值,
136 | typename decay<_Args>::type...>::value,
有人可以一步一步解释我吗.
Can someone explain me, step by step.
对于这个问题的任何提示,我将不胜感激.
I would be grateful for any hint on this question.
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
struct Base
{
Base() { std::cout << " Base::Base()\n"; }
// Note: non-virtual destructor is OK here
~Base() { std::cout << " Base::~Base()\n"; }
};
struct Derived: public Base
{
Derived() { std::cout << " Derived::Derived()\n"; }
~Derived() { std::cout << " Derived::~Derived()\n"; }
};
void thr(std::shared_ptr<Base> p)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
std::shared_ptr<Base> lp = p; // thread-safe, even though the
// shared use_count is incremented
{
static std::mutex io_mutex;
std::lock_guard<std::mutex> lk(io_mutex);
std::cout << "local pointer in a thread:\n"
<< " lp.get() = " << lp.get()
<< ", lp.use_count() = " << lp.use_count() << '\n';
}
}
int main()
{
std::shared_ptr<Base> p = std::make_shared<Derived>();
std::cout << "Created a shared Derived (as a pointer to Base)\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
std::thread t1(thr, p), t2(thr, p), t3(thr, p);
p.reset(); // release ownership from main
std::cout << "Shared ownership between 3 threads and released\n"
<< "ownership from main:\n"
<< " p.get() = " << p.get()
<< ", p.use_count() = " << p.use_count() << '\n';
t1.join(); t2.join(); t3.join();
std::cout << "after joining the threads\n" <<
" p.get() = " << p.get() << ", p.use_count() " <<p.use_count() << std::endl;
std::cout << "All threads completed, the last one deleted Derived\n";
}
输出:
Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
p.get() = 0x57be80, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
p.get() = 0, p.use_count() = 0
local pointer in a thread:
lp.get() = 0x57be80, lp.use_count() = 4
local pointer in a thread:
lp.get() = 0x57be80, lp.use_count() = 3
local pointer in a thread:
lp.get() = 0x57be80, lp.use_count() = 2
Derived::~Derived()
Base::~Base()
after joining the threads
p.get() = 0, p.use_count() 0
All threads completed, the last one deleted Derived
推荐答案
传递给 std :: thread
构造函数的参数将被复制,然后作为右值转发给在新版本中运行的函数线.因此,当您创建这样的 std :: thread
时:
The arguments passed to the std::thread
constructor will be copied and then forwarded as rvalues to the function that runs in the new thread. So when you create a std::thread
like this:
std::thread t1(thr, p)
参数 p
将被复制,然后作为右值转发.如果函数 thr
需要一个左值引用,则不能使用右值来调用它.
the argument p
will be copied, then forwarded as an rvalue. If the function thr
expects an lvalue reference then it can't be called with an rvalue.
静态断言告诉您不能使用右值 shared_ptr< Base>
调用 thr(shared_ptr< Base>)
.(在添加静态断言之前,您只是从 std :: thread
的内心深处得到了一个可怕的模板实例化错误,现在的想法是,它告诉您英语的问题是什么.)
The static assertion is telling that you that you can't call thr(shared_ptr<Base>&)
with an rvalue shared_ptr<Base>
. (Before I added the static assertion you just got a horrible template instantiation error from deep inside the guts of std::thread
, now the idea is that it tells you what's wrong in English).
将引用传递给函数的解决方案是使用 std :: ref
函数创建 reference_wrapper
对象:
The solution to passing a reference into the function is to use the std::ref
function to create a reference_wrapper
object:
std::thread t1(thr, std::ref(p))
这将创建一个 std :: reference_wrapper< std :: shared_ptr< Base>>
,将其复制并转发为 thr 作为右值,然后将该右值可以转换为 shared_ptr< Base>&
来初始化 thr
函数的参数.
This will create a std::reference_wrapper<std::shared_ptr<Base>>
which gets copied and forwarded to thr
as an rvalue, and then that rvalue can be converted to shared_ptr<Base>&
to initialize the parameter of the thr
function.
https://en.cppreference上也对此做了清楚的解释.com/w/cpp/thread/thread/thread#Notes
这篇关于为什么编译器抱怨std :: thread参数在转换为右值后必须是可调用的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!