• c++学习之十四


    1)利用std::function实现回调函数,实现生产者及消费者模型

    // 254、回调函数的实现
    // 在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。
    // 示例:
    
    // 254、回调函数的实现
    // 在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。
    // 示例:
    #include 
    #include 
    #include                       // 线程类头文件。
    #include                       // 互斥锁类的头文件。
    #include                       // deque容器的头文件。
    #include                       // queue容器的头文件。
    #include   // 条件变量的头文件。
    #include 
    using namespace std;
    
    void show(const string& str)
    {
        cout<<"handle dat: "<<str<<endl;
    }
    
    struct B
    {
        void show(const string& str)
        {
            cout<<"class B handle dat: "<<str<<endl;
        }
    };
    
    class A
    {
    private:
        mutex mtx;
        condition_variable cond;
        queue<string,deque<string>> q;
        function<void(const string&)> callBack;
    public:
        // 注册回调函数,回调函数只有一个参数(消费者接收到的数据)。
        template<typename Fn,typename ...Args>
        void callBackFun(Fn&& fn,Args&&... args)
        {
            callBack = bind(forward<Fn>(fn),forward<Args>(args)...,std::placeholders::_1);
        }
        void incache(int num) //生成数据,num指定数据的个数
        {
            lock_guard<mutex> lock(mtx);
            for(int i = 0; i < num; i++)
            {
                static int sn = 1;
                string tmp = to_string(sn++) + "号";
                q.push(tmp); //把生产出来的数据入队列
            }
            // cond.notify_one();
            cond.notify_all(); //唤醒全部条件变量阻塞的线程
        }
        void outcache(void)
        {
            while(1)
            {
                unique_lock<mutex> lock(mtx);
                cond.wait(lock,[this]{return !q.empty();});
                string str = q.front();
                q.pop();
                cout<<"thread id: "<<this_thread::get_id()<<" recv msg "<<str<<endl;
                lock.unlock(); //手工解锁
                callBack(str); //回调函数,处理出队的数据(相当于数据消费掉)
            }
        }
    };
    int main()
    {
        A a;
        a.callBackFun(show);
    
        B b;
        a.callBackFun(&B::show,&b);
        thread t1(&A::outcache,&a); //创建消费者线程t1;
        thread t2(&A::outcache,&a); //创建消费者线程t2;
        thread t3(&A::outcache,&a); //创建消费者线程t3;
    
        this_thread::sleep_for(std::chrono::seconds(2));
        a.incache(2); //生产2个数据
        this_thread::sleep_for(std::chrono::seconds(3));
        a.incache(5); //生产5个数据    
        t1.join();
        t2.join();
        t3.join();
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    //输出结果:
    thread id: 140711377970944 recv msg 1号
    class B handle dat: 1号
    thread id: 140711377970944 recv msg 2号
    class B handle dat: 2号
    thread id: 140711386363648 recv msg 3号
    class B handle dat: 3号
    thread id: 140711377970944 recv msg 4号
    class B handle dat: 4号
    thread id: 140711394756352 recv msg 5号
    class B handle dat: 5号
    thread id: 140711386363648 recv msg 6号
    class B handle dat: 6号
    thread id: 140711377970944 recv msg 7号
    class B handle dat: 7号

    2)移动构造函数和移动赋值函数
    类名(const 类名&& 源对象){…} //移动构造函数
    类名& operator=(const 类名& 源对象){…} //移动赋值函数

    #include 
    #include
    
    using namespace std;
    
    class A
    {
    public:
    	A()=default;
    	int* iPtr = nullptr; //这里nullptr必须写;
    	void getMemory()
    	{
    		if(iPtr == nullptr)
    		{
    			iPtr = new int;
            	memset(iPtr, 0, sizeof(int));   // 初始化已分配的内存。			
    		}
    	}
    
    	A(const A& src) //拷贝构造函数
    	{
    		cout<<"拷贝分配内存"<<endl;		
    		if(iPtr == nullptr)
    		{
    			getMemory();
    		}
    		*iPtr = *src.iPtr;
    	}
    
    
    	A& operator=(const A& src)
    	{
    		cout<<"拷贝赋值运算符分配内存"<<endl;		
    		if(iPtr == nullptr)
    		{
    			getMemory();
    		}
    		*iPtr = *src.iPtr;		
    		return *this;
    	}
    
    	A(A&& src) //移动构造函数
    	{
    		cout<<"调用了移动构造函数"<<endl;
    		if(iPtr != nullptr) delete iPtr;
    		iPtr = src.iPtr; //这句话是最根本的,不能写成 *iPtr = *src.iPtr;
    		src.iPtr = nullptr;
    	}
    
    	A& operator=(A&& src)
    	{
    		cout<<"调用了移动赋值运算符函数"<<endl;
    		if(iPtr != nullptr) delete iPtr;
    		iPtr = src.iPtr; //这句话是最根本的,不能写成 *iPtr = *src.iPtr;
    		src.iPtr = nullptr;
    		return *this;
    	}
    };
    
    int main()
    {
    	A a;
    	a.getMemory();
    	*a.iPtr = 10;
    	cout<<"*iPtr data is: "<<*a.iPtr<<endl;
    
    	A a1(a);
    	cout<<"*iPtr1 data is: "<<*a1.iPtr<<endl; //调用拷贝构造函数
    
    	A a3;
    	a3 = a;
    	cout<<"*iPtr3 data is: "<<*a3.iPtr<<endl; //调用拷贝赋值运算符成员函数
    
    	auto f = [] { A aa; aa.getMemory(); *aa.iPtr = 8; return aa; }; 
    	A a4 = f();
    	cout<<"*iPtr4 data is: "<<*a4.iPtr<<endl; //调用了移动构造函数
    
    	A a5;
    	a5 = f();
    	cout<<"*iPtr5 data is: "<<*a5.iPtr<<endl; //调用了移动构造函数	
    	return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    //输出结果如下:
    *iPtr data is: 10
    拷贝分配内存
    *iPtr1 data is: 10
    拷贝赋值运算符分配内存
    *iPtr3 data is: 10
    调用了移动构造函数
    调用了移动构造函数
    *iPtr4 data is: 8
    调用了移动构造函数
    调用了移动赋值运算符函数
    *iPtr5 data is: 8

    3) 委托构造和继承构造

    .1)委托构造,【委托构造必须在同一个类里】;
    #include 
    using namespace std;
    //一旦使用委托构造,就不能在初始化列表中初始化其它的成员变量
    class A
    {
    public:
    	A(int a):a_(a){cout<<"a constructor----"<<endl;}
    	A(int a,string b):A(a) //A(int a,int b):A(a),b_(b)是错误的,//委托构造不能有其他的成员初始化列表
    	{ 
    		this->str_ = b;
    		cout<<"委托构造 "<<b<<endl;
    	}
    private:
    	int a_;
    	string str_;
    };
    
    int main(void)
    {
    	A a1(1); //没有调用委托构造函数
    	A a2(11,"hello world"); //调用了委托构造函数
    	return 0;
    }.2)继承构造
    #include 
    using namespace std;
    
    class AA       // 基类。
    {
    public:
        int      m_a;
        int      m_b;
        // 有一个参数的构造函数,初始化m_a
        AA(int a) : m_a(a) { cout << "base  AA(int a)" << endl; }
        // 有两个参数的构造函数,初始化m_a和m_b
        AA(int a, int b) : m_a(a), m_b(b) { cout << "base   AA(int a, int b)" << endl; }
    };
    
    class BB :public AA       // 派生类。
    {
    public:
        double   m_c;
        using AA::AA;     // 使用基类的构造函数。构造函数继承!!!
        // 有三个参数的构造函数,调用A(a,b)初始化m_a和m_b,同时初始化m_c
        BB(int a, int b, double c) : AA(a, b), m_c(c) {
            cout << " derived BB(int a, int b, double c)" << endl;
        }
        void show() { cout << "m_a=" << m_a << ",m_b=" << m_b << ",m_c=" << m_c << endl; }
    };
    
    int main()
    {
        // 将使用基类有一个参数的构造函数,初始化m_a
        BB b1(10);       
        b1.show();
    
        // 将使用基类有两个参数的构造函数,初始化m_a和m_b
        BB b2(10,20);  
        b2.show();
    
        // 将使用派生类自己有三个参数的构造函数,调用A(a,b)初始化m_a和m_b,同时初始化m_c
        BB b3(10,20,10.58);  
        b3.show();
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    const关键字从功能上来说有双重语义:只读变量和修饰常量。
    using 和 typedef都可以设置模板别名,但using可以用于部分模板具体化;
    传统方法用sprintf()和snprintf()函数把数值转换为char字符串;用atoi()、atol()、atof()把char字符串转换为数值。
    C++11提供了新的方法,在数值类型和string字符串之间转换。“to_string()”
    默认情况下,由lambda函数生成的类是const成员函数,所以变量的值不能修改。如果加上mutable,相当于去掉const。这样上面的限制就能讲通了
    4)字符串转整形的函数“stoi”的使用方法:

    #include 
    #include
    #include
    
    using namespace std;
    int main()
    {
    	string str("1q2A345");
    	size_t pos = 0; //pos,是传出参数,存放从哪个字符开始无法继续解析的位置
    	int val = stoi(str, &pos, 10);
    	cout<<pos<<endl;  //1
    	cout<<val<<endl; //1
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5)异常处理的案例

    #include 
    using namespace std;
    
    int main(int argc, char* argv[])
    {
    	try
    	{
    		int ii;
    		cin>>ii;
    		if(ii == 1)
    		{
    			cout<<"111111111111"<<endl;
    			throw(12);
    		}
    		if(ii == 2)
    		{
    			cout<<"222222"<<endl;
    			throw("const char* number");			//抛出的是const char*
    		}		
    		if(ii == 3)
    		{
    			cout<<"3333"<<endl;
    			throw string("string number");			//抛出的是string
    		}		
    	}
    	catch(int tmp)
    	{
    		cout<<"int type: tmp "<<tmp<<endl;
    	}
    	
    	catch(const char* str) //const char*
    	{
    		cout<<"string type: tmp "<<str<<endl;
    	}	
    
    	catch(string str) 
    	{
    		cout<<"string type: tmp "<<str<<endl;
    	}		
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    6)读文件时,badbid,failbit,goodbit,eofbit的flag的变化及解释:
    //测试文件名字:123.txt,其内容是"aaa";

    #include 
    #include   // ifstream类需要包含的头文件。
    #include      // getline()函数需要包含的头文件。
    using  namespace std;
    
    int main()
    {
    	ifstream fin("123.txt", ios::in);
    
    	if (fin.is_open() == false)
    	{
    		cout << "打开文件" << R"(D:\data\txt\test.txt)" << "失败。\n";  return 0;
    	}
    	// fin.good();//正常读取文件时返回true
    	// fin.fail();/在文件到达结尾或者出现其他输入错误如内存不足时返回true
    	// fin.eof();//当文件到达结尾的返回true。
    	string buffer;
    	while (true)
    	{
    		fin >> buffer;
    		cout << "eof()=" << fin.eof() << ",good() = " << fin.good() << ", bad() = " << fin.bad() << ", fail() = " << fin.fail() << endl;
    		if (fin.eof() == true) break;
    
    		cout << buffer << endl;
    	}
    
    	fin.close();	   // 关闭文件,fin对象失效前会自动调用close()。
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    //输出结果是:
    eof()=0,good() = 1, bad() = 0, fail() = 0
    aaa
    eof()=1,good() = 0, bad() = 0, fail() = 1

  • 相关阅读:
    Web前端入门(十三)CSS复合选择器
    Spring 6【方法参数校验、SpingAOP介绍、Schema-based方式实现AOP 】(十四)-全面详解(学习总结---从入门到深化)
    云原生--kubectl命令汇总
    基于问题驱动法的计算机组成原理教学研究
    数仓模型设计方法论
    23上半年下午题
    vue项目中使用antvX6新手教程,附demo案例讲解(可拖拽流程图、网络拓扑图)
    Java-Redis-Redisson配置
    产品经理常用的工具有哪些?
    如何解决kafka rebalance导致的暂时性不能消费数据问题
  • 原文地址:https://blog.csdn.net/qq_30143193/article/details/132846448