C++查漏补缺

C++查漏补缺


目录

         typedef

const与指针

构造函数_使用初始化列表来初始化字段

#define条件编译

c++抽象类

C++11新特性之 “=default”

C++中std::allocator的使用

unique_lock

mutex

auto

unique_ptr智能指针

多线程编程之条件变量notify_one()、notify_all()

join()函数

std::condition_variable详解

参考资料


因为参加比赛,最近在看2019年的RM开源代码

整理了一些之前没有仔细看过或者忘差不多的c++知识点,自用

typedef

用法一:定义了一种类型的别名,不是宏替换,可以用于一次定义多个指针

typedef char* PCHAR;

PCHAR pa,pb;

用法二:定义结构体时使用,以后可以少写struct

typedef struct point2D{
    int x;
    int y;
}POINT2D;
POINT2D pa;

用法三:定义与平台无关的类型

比如用HPINT表示此平台最高精度的实数类型

typedef long double HPNUM;

在另一个不支持long double的平台上,只需要将这行修改成

typedef double HPNUM;

如果不支持double,则改成

typedef float HPNUM;

用法四:

为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。(摘自https://blog.csdn.net/andrewniu/article/details/80566324)

1. 原声明:int *(*a[5])(int, char*);
变量名为a,直接用一个新别名pFun替换a就可以了:
typedef int *(*pFun)(int, char*); 
原声明的最简化版:
pFun a[5];

2. 原声明:void (*b[10]) (void (*)());
变量名为b,先替换右边部分括号里的,pFunParam为别名一:
typedef void (*pFunParam)();
再替换左边的变量b,pFunx为别名二:
typedef void (*pFunx)(pFunParam);
原声明的最简化版:
pFunx b[10];

3. 原声明:doube(*)() (*e)[9]; 
变量名为e,先替换左边部分,pFuny为别名一:
typedef double(*pFuny)();
再替换右边的变量e,pFunParamy为别名二
typedef pFuny (*pFunParamy)[9];
原声明的最简化版:
pFunParamy e;

理解复杂声明可用的“右左法则”:
从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例:
int (*func)(int *p);
首 先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明 (*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。
int (*func[5])(int *);
func 右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰 func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指 针,它指向的函数具有int*类型的形参,返回值类型为int。

也可以记住2个模式:
type (*)(....)函数指针 
type (*)[]数组指针

typedef的使用注意事项:

1.当const和typedef一起出现时,typedef不会是简单的字符串替换

2.typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如:
typedef static int INT2; //不可行

const与指针

const int * pOne;    //指向整形常量 的指针,它指向的值不能修改

int * const pTwo;    //指向整形的常量指针 ,它不能在指向别的变量,但指向(变量)的值可以修改。 

const int *const pThree;  //指向整形常量 的常量指针 。它既不能再指向别的常量,指向的值也不能修改。

理解这些声明的技巧在于,查看关键字const右边来确定什么被声明为常量 ,如果该关键字的右边是类型,则值是常量;如果关键字的右边是指针变量,则指针本身是常量。

构造函数_使用初始化列表来初始化字段

Point::Point(double a,double b):x(a),y(b){
...
}

#define条件编译

可以在编译的时候通过#define设置编译环境,避免重复编译或者仅在某种条件下才编译,具体例子见链接

https://wenku.baidu.com/view/3d7b2c26a4e9856a561252d380eb6294dd882214.html

c++抽象类

c++接口是使用抽象类实现的,如果类中至少有一个函数为纯虚函数,则这个类就是抽象类.

纯虚函数在声明中使用"=0"

抽象类不能被实例化,只能用于接口,一个抽象类的子类要被实例化需要实现所有的纯虚函数

#include
#include
using namespace std;

class country{
    protected :
        string name;
        int age;
        double flag[10][10];
    public :
        country(string n,int a):name(n),age(a){}
        virtual void sayHello()=0;
};

class russia:public country{

    public :
        russia(string n,int a):country(n,a){}
        void sayHello(){
            cout<<"hello "+name<

C++查漏补缺_第1张图片

另外需要注意的是C++ 中,如果继承链上存在虚继承的基类,则最底层的子类要负责完成该虚基类部分成员的构造。

https://blog.csdn.net/qq_28954601/article/details/70227589

C++11新特性之 “=default”

defaulted 函数特性仅用于类的特殊成员函数,且该特殊成员函数没有默认参数。

用于编译器自动生成函数定义体

C++中std::allocator的使用

标准库allocator类定义在头文件memory中,它帮助我们将内存分配和对象构造分离开来它提供一种类型感知的内存分配方法,它分配的内存是原始的、未构造的。类似vector,allocator是一个模板。为了定义一个allocator对象,我们必须指明这个allocator可以分配的对象类型。当一个allocator对象分配内存时,它会根据给定的对象类型来确定恰当的内存大小和对齐位置。

释放内存通过调用deallocate来完成。我们传递给deallocate的指针不能为空,它必须指向由allocate分配的内存。而且,传递给deallocate的大小参数必须与调用allocate分配内存时提供的大小参数具有一样的值。

https://blog.csdn.net/fengbingchun/article/details/78943527/

unique_lock

互斥锁保证了线程间的同步,但是却将并行操作变成了串行操作,这对性能有很大的影响,所以我们要尽可能的减小锁定的区域,也就是使用细粒度锁

这一点lock_guard做的不好,不够灵活,lock_guard只能保证在析构的时候执行解锁操作,lock_guard本身并没有提供加锁和解锁的接口,但是有些时候会有这种需求。

使用unique_lock。它提供了lock()unlock()接口,能记录现在处于上锁还是没上锁状态,在析构的时候,会根据当前状态来决定是否要进行解锁(lock_guard就一定会解锁)。

class LogFile {
    std::mutex _mu;
    ofstream f;
public:
    LogFile() {
        f.open("log.txt");
    }
    ~LogFile() {
        f.close();
    }
    void shared_print(string msg, int id) {

        std::unique_lock guard(_mu);
        //do something 1
        guard.unlock(); //临时解锁

        //do something 2

        guard.lock(); //继续上锁
        // do something 3
        f << msg << id << endl;
        cout << msg << id << endl;
        // 结束时析构guard会临时解锁
        // 这句话可要可不要,不写,析构的时候也会自动执行
        // guard.ulock();
    }

};

mutex

mutex用于多线程编程,当临界区被互斥访问时用作信号,不支持递归,常用的成员函数有lock()和unlock()

#include 
#include 
#include 
#include 

using namespace std;

mutex mtx;

void fn1()
{
	for (int i = 0; i < 5; i++)
	{
		mtx.lock();
		cout << "线程" << this_thread::get_id() << ":" << "The thread1 is running !" << endl;
		mtx.unlock();
	}
}

void fn2()
{
	for (int i = 0; i < 5; i++)
	{
		mtx.lock();
		cout << "线程" << this_thread::get_id() << ":" << "The thread2 is running !" << endl;
		mtx.unlock();
	}
}

int main()
{
	thread t1(fn1);
	thread t2(fn2);
	t1.detach();
	t2.detach();

	this_thread::sleep_for(chrono::milliseconds(1000));
	getchar();
	return 0;
}

auto

根据后面的值,自己推测前面的类型是什么,用于简化变量初始化

用auto声明的变量必须初始化

https://blog.csdn.net/lwgkzl/article/details/82110068

unique_ptr智能指针

unique_ptr对象包装一个原始指针,并负责其生命周期。当该对象被销毁时,会在其析构函数中删除关联的原始指针。
unique_ptr具有->*运算符重载符,因此它可以像普通指针一样使用。

 

多线程编程之条件变量notify_one()、notify_all()

用于唤醒阻塞的线程,前者只唤醒等待队列中的第一个线程,不存在锁争用,能够立即获得锁,后者会唤醒所有等待队列中阻塞的线程,存在锁争用,只有一个线程能获得,其他线程会进入轮询状态.

join()函数

join()函数的作用是让主线程的等待该子线程完成,然后主线程再继续执行。这种情况下,子线程可以安全的访问主线程中的资源。子线程结束后由主线程负责回收子线程资源。一个子线程只能调用join()和detach()中的一个,且只允许调用一次。可以调用joinable()来判断是否可以成功调用join()或detach()。

std::condition_variable详解

当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。

wait_for() 可以指定一个时间段,在当前线程收到通知或者指定的时间 rel_time 超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_for 返回,剩下的处理步骤和 wait() 类似。

 

参考资料


https://blog.csdn.net/andrewniu/article/details/80566324

https://blog.csdn.net/qq_28954601/article/details/70227589

https://www.jianshu.com/p/34d219380d90

https://blog.csdn.net/konglongdanfo1/article/details/86764454

https://blog.csdn.net/feikudai8460/article/details/109604690?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-3&spm=1001.2101.3001.4242

你可能感兴趣的:(日常自用,c++)