std::具有指向数据成员的指针的线程
std::thread with pointer to data member
我在cppreference上阅读了std::thread文档(我知道并不总是100%准确(,并注意到当传递"指向数据成员的指针"(而不是"指向成员函数的指针"(作为其第一个参数(f
(和所需类的对象作为其第二个参数(复制到线程本地存储后的t1
(时,std::thread
的行为定义如下:
如果N==1并且f是指向类的成员数据对象的指针,则访问它。对象的值将被忽略。实际上,执行以下代码:t1.*f如果并且t1的类型是T、对T的引用或对从T导出的类型的引用。(*t1(.*f否则。
现在,我不打算以这种方式使用std::thread
,但我对这个定义感到困惑。显然,唯一会发生的事情是访问数据成员并忽略该值,这似乎根本不会产生任何可观察到的副作用,这意味着(据我所知(这可能是一个否定。(我可能遗漏了一些明显的东西…?(
起初,我认为这可能是印刷错误,意思是说数据成员被访问,然后被调用(因为它可能是一个可调用的对象,即使它不是一个函数(,但我在GCC-4.7中用以下代码进行了测试,实际上没有调用:
#include <iostream>
#include <thread>
struct S
{
void f() {
std::cout << "Calling f()" << std::endl;
}
struct {
void operator()() {
std::cout << "Calling g()" << std::endl;
}
} g;
};
int main(int, char**)
{
S s;
s.f(); // prints "Calling f()"
s.g(); // prints "Calling g()"
std::cout << "----" << std::endl;
auto x = &S::f; // ptr-to-mem-func
auto y = &S::g; // ptr-to-data-mem
(s.*x)(); // prints "Calling f()"
(s.*y)(); // prints "Calling g()"
std::cout << "----" << std::endl;
std::thread t(x, &s);
t.join();
// "Calling f()" printed by now
std::thread u(y, &s);
u.join();
// "Calling g()" not printed
return 0;
}
这个定义有没有什么目的似乎什么都没有?为什么不让传递"指向数据成员的指针可调用"就像传递"指向成员函数的指针"一样,并让传递"数据成员的指示器不可调用"成为一个错误呢?事实上,这似乎是实现它的最简单方法,因为调用"可调用的数据成员指针"与在其他上下文中调用"成员函数指针"具有等效的语法(除非模板专用化和SFINAE规则的变幻莫测使其难以同等对待…?(
这不是我实际代码所需要的东西,但这个定义的存在让我怀疑我错过了一些基本的东西,这让我很担心……有人能启发我吗?
这是因为C++11标准不仅定义了线程的启动方式,还定义了std::bind
和std::function
的工作方式。
事实上,C++11标准的第30.3.1.2/3段规定了类std::thread
:的可变构造函数
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
效果:构造线程类型的对象。执行的新线程执行
INVOKE (DECAY_- COPY ( std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...)
,并调用CCD_ 10在构造线程中被评估。此调用的任何返回值都是已忽略。[…]
忽略DECAY_COPY
的作用(与问题无关(,这就是第20.8.2段定义INVOKE
伪函数的方式:
定义INVOKE(f,t1,t2,…,tN(如下:
--(t1.*f((t2,…,tN(当f是指向类T的成员函数的指针并且t1是类型T或对类型T的对象的引用或对从T派生的类型的对象的参考;
--((*t1(.*f((t2,…,tN(当f是指向类T的成员函数的指针并且t1不是前一项中所述的类型;
--当N==1并且f是指向类T的成员数据的指针并且t1是类型T或a的对象时对类型为T的对象的引用或对从T派生的类型的对象的参考;
--(*t1(.*f当N==1并且f是指向类T的成员数据的指针并且t1不是类型之一时如前一项所述
--f(t1,t2,…,tN(。
现在的问题变成了:
为什么C++11标准会这样定义
INVOKE
功能?
答案是这里。
- 如何检索指向在单独线程上运行的函数的移动指针?
- 如何将'this'指针传递给C++ WinAPI 线程?
- 从子线程访问指针
- 将字符串指针传递到C++和Xcode 11.1中不同线程上运行的函数
- 通过std::shared_ptr使用Rcpp和RcppParallel的线程安全函数指针
- 在多线程函数中返回共享的常量指针会导致计时问题吗?
- 线程中的成员函数指针
- 如何安全地终止线程?(使用指针)C++
- 指向成员对象的指针 - 中断线程
- 是否可以访问非线程安全容器内指针指向的值(线程安全映射中的条目)?
- 如何抓取指向Qt中弹出对话框的指针,该对话框阻止了QTest中的UI线程
- 将指针传递到另一个线程的正确方法
- CPP:如何使用需要指针的方法创建线程
- 启动线程会导致指针初始化时出现分段错误
- 是否访问指针元组和互斥锁线程安全
- 在容器中存储指向对象的指针时的线程安全
- 为什么当我在构造函数中创建线程时,实例化对象和对象的指针的行为不同
- 指针在不同的线程中获得错误的价值
- C++ 线程函数指针实现返回错误无效使用非静态成员函数
- 指向对象初始化的静态指针——线程安全