• std::get<C++11多线程库>(07):向线程函数传递参数(3)


     
     1  /*
     2  * 实例场景:
     3  * 2. std::thread 构造函数的第一个参数为成员函数时,参数的传递。
     4  *    传递方式:std::thread第一个参数为成员函数的函数指针, std::thread 从第二个开始的参数,依次传递给成员函数的参数表
     5  *      Obj obj;
     6  *      std::thread t(&Obj::func, &obj, param1);
     7  *      std::thread t(&Obj::func, &obj, param1, param2, ..., paramn);
     8  *
     9  *  * * 分别就参数的几种常见形式进行讨论:
    10  *
    11  *      Object obj;
    12  *      Param param(10);
    13  *
    14  *        a) 参数为值类型,    例如 Param。     func形参地址与实参地址不同,发生了: 拷贝构造+移动构造。
    15  *           std::thread t(&Object::func, &obj, param);
    16  *
    17  *        b) 参数为引用类型,  例如 Param &。   func形参地址与实参地址分两种方式而不同  !!!请注意:默认变量类型和自定义类类型的情况并不一样!!!
    18  *           b-1) 默认方式
    19  *           std::thread t(&Object::func, &obj, param);  形参地址与实参地址不同, 发生了:拷贝构造。
    20  *
    21  *           b-2) std::ref() 方式
    22  *           std::thread t(&Object::func, &obj, std::ref(param)); 形参地址与实参地址相同, 未发生拷贝构造,未发生移动构造
    23  *
    24  *        c) 参数为指针类型,  例如 int *。   func形参地址与实参地址相同,未发生拷贝。
    25  *          std::thread t(&Object::func, &obj, &param);
    26  */

     * 问-思考:
     * 2. std::thread 构造函数执行时,不同的参数类型在传递时,都发生了什么事情?比如:值类型,引用类型,指针类型
     
     1 //! [2] ====================== *实例场景-2=====+=====问-思考-2 *==================
     2 template<typename T>
     3 class luckyBear{
     4 public:
     5     luckyBear(T t):m_t(t){
     6         std::cout<<"luckyBear<"<<_typeName()<<"> 构造函数执行..."<<std::endl;
     7     }
     8     luckyBear(luckyBear & other):m_t(other.m_t){
     9         std::cout<<"luckyBear<"<<_typeName()<<"> 拷贝构造函数执行..."<<std::endl;
    10     }
    11     luckyBear(luckyBear &&other){
    12         m_t = std::move(other.m_t);
    13         std::cout<<"luckyBear<"<<_typeName()<<"> 移动构造函数执行..."<<std::endl;
    14     }
    15     ~luckyBear(){
    16         std::cout<<"luckyBear<"<<_typeName()<<"> 析构函数执行..."<<std::endl;
    17     }
    18 
    19     void operator=(luckyBear &other){
    20         m_t = other.m_t;
    21         std::cout<<"luckyBear<"<<_typeName()<<"> 赋值运算符函数执行..."<<std::endl;
    22     }
    23 
    24     void operator=(luckyBear &&other){
    25         m_t = std::move(other.m_t);
    26         std::cout<<"luckyBear<"<<_typeName()<<"> 移动赋值运算符函数执行..."<<std::endl;
    27     }
    28 
    29     T value(){
    30         return m_t;
    31     }
    32 
    33 private:
    34     std::string _typeName(){
    35        const std::type_info & _type = typeid(T);
    36        return _type.name();
    37     }
    38 
    39 private:
    40     T m_t;
    41 };
    42 
    43 
    44 template<typename T>
    45 class thread_test : public luckyBear<T>{
    46 
    47 public:
    48     thread_test():luckyBear<T>(0){}
    49 };
    50 
    51 typedef luckyBear<int> VType;          //Value type
    52 typedef luckyBear<int>& RType; //Reference type
    53 typedef luckyBear<int>* PType; //Pointer type
    54 
    55 class thread_construct{
    56 
    57 public:
    58     void func1(VType v){
    59         std::cout<<v.value()<<std::endl;
    60     }
    61 
    62     void func2(RType rv){
    63         std::cout<<rv.value()<<std::endl;
    64     }
    65 
    66     void func3(PType pv){
    67         std::cout<<pv->value()<<std::endl;
    68     }
    69 };
     1 //! [2-1] 值类型传递: (1次)拷贝构造 + (1次)移动构造
     2 
     3 //分析
     4 /*
     5   1-从局部变量到线程的独立空间中,发生了拷贝构造;
     6   2-从线程的独立空间到线程入口函数,发生了移动构造;
     7   3-形参和实参地址不同;
     8 */
     9 int main(int argc, char *argv[]){
    10 
    11     VType vt(10);
    12 
    13     thread_construct _c;
    14     std::thread _t1(&thread_construct::func1, &_c, vt);
    15 
    16     _t1.join();
    17     std::cout<<"...lucky bear..."<<std::endl;
    18     return 0;
    19 
    20 }
    21 //打印输出:
    22 /*
    23     luckyBear<int> 构造函数执行...
    24     luckyBear<int> 拷贝构造函数执行...
    25     luckyBear<int> 移动构造函数执行...
    26     10
    27     luckyBear<int> 析构函数执行...
    28     luckyBear<int> 析构函数执行...
    29     ...lucky bear...
    30     luckyBear<int> 析构函数执行...
    31 */
    32 //! [2-1]
     1 //! [2-2-1] 引用类型传递--默认方式: (1次)拷贝构造
     2 
     3 //分析
     4 /*
     5     1. 从局部变量到线程的独立空间中,发生了拷贝构造, “默认参数要拷贝到线程独立内存中,即使参数是引用的形式”;
     6     2. 从线程的独立空间到线程入口函数,属于常规的给引用参数传值, 引用即别名,不开辟新空间;
     7     3. 形参和实参地址不同;
     8 */
     9 int main(int argc, char *argv[]){
    10 
    11     VType vt(10);
    12 
    13     thread_construct _c;
    14     std::thread _t1(&thread_construct::func2, &_c, vt);   //默认方式
    15 
    16     _t1.join();
    17     std::cout<<"...lucky bear..."<<std::endl;
    18     return 0;
    19 }
    20 //打印输出:
    21 /*
    22 luckyBear<int> 构造函数执行...
    23 luckyBear<int> 拷贝构造函数执行...
    24 10
    25 luckyBear<int> 析构函数执行...
    26 ...lucky bear...
    27 luckyBear<int> 析构函数执行...
    28 */
    29 //! [2-2-1]
     1 //! [2-2-2] 引用类型传递--std::ref()方式:   不发生拷贝构造,不发生移动构造
     2 
     3 //分析
     4 /*
     5     1. 从局部变量到线程的独立空间中,属于常规的给引用参数传值, 引用即别名,不开辟新空间;
     6     2. 从线程的独立空间到线程入口函数,属于常规的给引用参数传值, 引用即别名,不开辟新空间;
     7     3. 形参和实参地址相同;
     8     4. std::ref() 方式传递引用类型参数,可以做到线程内对参数的修改会作用到线程外部的实参变量,反过来也是一样。
     9 */
    10 int main(int argc, char *argv[]){
    11 
    12     VType vt(10);
    13 
    14     thread_construct _c;
    15     std::thread _t1(&thread_construct::func2, &_c, std::ref(vt));  //std::ref() 方式
    16 
    17     _t1.join();
    18     std::cout<<"...lucky bear..."<<std::endl;
    19     return 0;
    20 }
    21 //打印输出:
    22 /*
    23 luckyBear<int> 构造函数执行...
    24 10
    25 ...lucky bear...
    26 luckyBear<int> 析构函数执行...
    27 */
    28 //! [2-2-2]
     1 //! [2-3-1] 指针类型传递--默认方式:   不发生拷贝构造,不发生移动构造
     2 
     3 //分析
     4 /*
     5     1. 从局部变量到线程的独立空间中,属于常规的给指针参数传值, 多个指针指向同一地址空间,不开辟新空间;
     6     2. 从线程的独立空间到线程入口函数,属于常规的给指针参数传值, 多个指针指向同一地址空间,不开辟新空间;
     7     3. 形参和实参地址相同;
     8     4. 默认方式方式传递指针类型参数,可以做到线程内对参数的修改会作用到线程外部的实参变量,反过来也是一样。
     9 */
    10 int main(int argc, char *argv[]){
    11 
    12     VType vt(10);
    13 
    14     thread_construct _c;
    15     std::thread _t1(&thread_construct::func3, &_c, &vt);  //默认方式
    16 
    17     _t1.join();
    18     std::cout<<"...lucky bear..."<<std::endl;
    19     return 0;
    20 }
    21 //打印输出:
    22 /*
    23 luckyBear<int> 构造函数执行...
    24 10
    25 ...lucky bear...
    26 luckyBear<int> 析构函数执行...
    27 */
    28 //! [2-3-1]
     1 //! [2-3-2] 指针类型传递--std::ref()方式:   不可以这样使用,编译报错
     2 
     3 //分析
     4 /*
     5 */
     6 int main(int argc, char *argv[]){
     7 
     8     VType vt(10);
     9 
    10     thread_construct _c;
    11 
    12     //error info: C2893:未能使函数模板(unkown-type std::invoke(_Callable &&, _Types &&...)专用化
    13     //std::thread _t1(&thread_construct::func3, &_c,std::ref(vt));  //std::ref() 方式
    14 
    15     //_t1.join();
    16     std::cout<<"...lucky bear..."<<std::endl;
    17     return 0;
    18 }
    19 //打印输出:
    20 /*
    21 */
    22 //! [2-3-2]
    23 //! [2]

    std::get<C++11多线程库>(07):向线程函数传递参数(4)

    原创文章, 转载请注明出处!

  • 相关阅读:
    关于数据库的基础知识
    Oracle数据库的上机作业
    PHP表单处理
    EasyUI DataGrid结合ThinkPHP实现增删改查操作———初学者
    Redis crackit
    nodeppt安装后,phantomjs不能运行了 Bad argument
    redis命令
    eclipse编辑web.xml很慢
    客制化jasperreport导出html的过程
    dynamicreport, JFreeChart
  • 原文地址:https://www.cnblogs.com/azbane/p/15335042.html
Copyright © 2020-2023  润新知