c++ learning fourteen

1) Use std::function to implement callback functions and implement producer and consumer models

// 254、回调函数的实现
// 在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。
// 示例:

// 254、回调函数的实现
// 在消息队列和网络库的框架中,当接收到消息(报文)时,回调用户自定义的函数对象,把消息(报文)参数传给它,由它决定如何处理。
// 示例:
#include <iostream>
#include <string>
#include <thread>                      // 线程类头文件。
#include <mutex>                      // 互斥锁类的头文件。
#include <deque>                      // deque容器的头文件。
#include <queue>                      // queue容器的头文件。
#include <condition_variable>  // 条件变量的头文件。
#include <functional>
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;
}

//Output result:
thread id: 140711377970944 recv msg No. 1
class B handle dat: No. 1
thread id: 140711377970944 recv msg No. 2 class
B handle
dat: No. 2 thread id: 140711386363648 recv msg No. 3
class B handle dat: No. 3
thread id: 140711377970944 recv msg No. 4
class B handle dat: No. 4
thread id: 140711394756352 recv msg No. 5
class B handle dat: No. 5 thread
id: 140711386363648 recv msg No. 6
class B handle dat: No. 6
thread id: 140 711377970944 recv msg No. 7
class B handle dat: No. 7

2) Move constructor and move assignment function
class name (const class name&& source object){…} //Move constructor class
name& operator=(const class name& source object){…} //Move assignment function

#include <iostream>
#include<string.h>

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;
}

//The output results are as follows:
*iPtr data is: 10
copy allocation memory
*iPtr1 data is: 10
copy assignment operator allocates memory
*iPtr3 data is: 10
The move constructor is
called The move constructor is called
*iPtr4 data is: 8
call The move constructor is
called and the move assignment operator function
*iPtr5 data is: 8

3) Delegate construction and inheritance construction

.1)委托构造,【委托构造必须在同一个类里】;
#include <iostream>
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 <iostream>
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();
}

The const keyword has dual semantics functionally: read-only variables and modified constants.
Both using and typedef can set template aliases, but using can be used for partial template reification; the
traditional method uses sprintf() and snprintf() functions to convert values ​​into char strings; use atoi(), atol(), atof() Convert char string to numeric value.
C++11 provides new methods for converting between numeric types and strings. "to_string()"
By default, the class generated by the lambda function is a const member function, so the value of the variable cannot be modified. If you add mutable, it is equivalent to removing const. In this way, the above restrictions can be explained.
4) How to use the function "stoi" that converts string to integer:

#include <iostream>
#include<string>
#include<string.h>

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;
}

5) Cases of exception handling

#include <iostream>
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;
}

6) When reading files, the changes and explanations of badbid, failbit, goodbit, and eofbit flags:
//Test file name: 123.txt, its content is "aaa";

#include <iostream>
#include <fstream>  // ifstream类需要包含的头文件。
#include <string>     // 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()。
}

//The output result is:
eof()=0,good() = 1, bad() = 0, fail() = 0
aaa
eof()=1,good() = 0, bad() = 0, fail( ) = 1

Guess you like

Origin blog.csdn.net/qq_30143193/article/details/132846448