c++最好用易用的新特性:
- auto/decltype https://blog.csdn.net/zyc2018/article/details/93591189
- nullptr
- range-for
- using
c++有哪些坑?
内存泄漏的解决方案:
- 智能指针
- 内存池
学习优秀的c++源码
- Nginx
- Leveldb
- Envoy
- Folly
- Boost
vector<int> month;
int cnt=1;
month.push_back(3);
for(int i=3;i<=monthCount;i++)
{
for(auto &e:month)
{
e++;
}
for(auto e:month)
{
if(e>=3)
{
cnt++;
month.push_back(1);
}
}
}
这段代码外层for中嵌套了两个range-for,但是第一个可以用,第二个是不行的,你看出原因了么?
第二个错误在于:range-for中向遍历的vector中添加了元素。
先给出结论:不能在range-for的循环体中改变遍历的容器的大小,即不允许遍历的同时添加或删除元素!
至于原因,其实也不难理解:
我们都知道,凡是使用了迭代器的循环体中都不能向迭代器所属的容器添加元素!(C++primer,5e,P99)
因为对于某些容器,向容器中添加或删除元素会导致迭代器失效,因此后续遍历操作都是未定义的。而STL各种容器失效的时机是不同的,感兴趣的可以参考这位大神的博客:http://blog.csdn.net/yangquanhui1991/article/details/52077562,所以才有C++primer中的上述金玉良言。
再回过来看为何range-for也不可以呢?
这是因为range-for底层实现时预存了容器的end()值,而一旦遍历的时候向该容器添加或删除元素,就会使该预存的end()失效,由上述迭代器失效的问题,就不难明白:range-for的循环体中不允许对该容器添加或删除元素!
因此上面代码中的第二个range-for应该改成普通for循环,并且不能使用迭代器遍历:
vector<int> month;
int cnt=1;
month.push_back(3);
for(int i=3;i<=monthCount;i++){
for(auto &e:month){
e++;
}
for(int i=0;i<month.size();i++){//不能使用range-for或迭代器遍历!
if(month[i]>=3){
cnt++;
month.push_back(1);
}
}
}
其实range-for的这个陷阱在C++ primer第五版里已经做出了警示,当时看书时也做了记号,只是这种问题真的只有自己犯过一两次错误后才能记得!而且这种错误一旦发生,很难发现错误根源,编译期无错误无警告,而且运行时不同编译器执行的结果可能不一样!因为迭代器失效后再执行后续循环将是未定义的行为,所以C++primer建议如果使用迭代器遍历,每次在插入或删除元素后都应该重新定位迭代器,对于这点在写程序时一定要有一个清醒的认识。
C++中#define宏定义的min与max函数
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
这样代码效率会特别高,比库函数要快
C++ explicit关键字详解
C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式)。
explicit关键字的作用就是防止类构造函数的隐式自动转换。
explicit关键字只对有一个参数的类构造函数有效, 如果类构造函数参数大于或等于两个时, 是不会产生隐式转换的, 所以explicit关键字也就无效了。
1、3次握手和4次挥手
2、TCP与UDP的区别
3、如果TCP连接出现问题该如何排查,说明排查的思路
连接断开或者出错,会返回一个错误码,errorNo 最后一次系统调用返回的错误码,来看错误的类型。
4、三元组算法问题
5、查询linux系统中的cup和内存占用率
如果查到具体是哪一个进程占用的比较多,你会怎么做?
如何能够降低程序的cpu或者内存的占用率
看是网络程序占用的还是业务逻辑计算功能占用的
如果是网络连接程序,你把网络断了,它还占用那么大,那么网络程序写的有问题
如果是逻辑计算功能占用,我把它的所有数据输入都去掉,如果它还占用那么大,那么业务逻辑计算程序就写的有问题。
6、什么时候使用多线程,什么时候使用多进程
7、单例模式在什么情况下使用,有什么好处
8、对于临界资源的访问有哪几种控制方式
9、什么是原子操作
10、有没有使用过线程池?
11、什么是互斥锁,什么是自旋锁?
读写锁特点:
读写锁有三种状态:读加锁状态、写加锁状态和不加锁状态
只有一个线程可以占有写状态的锁,但可以有多个线程同时占有读状态锁,这也是它可以实现高并发的原因。
当其处于写状态锁下,任何想要尝试获得锁的线程都会被阻塞,直到写状态锁被释放;
如果是处于读状态锁下,允许其它线程获得它的读状态锁,但是不允许获得它的写状态锁,直到所有线程的读状态锁被释放;
为了避免想要尝试写操作的线程一直得不到写状态锁,当处于读模式的读写锁接收到一个试图对其进行写模式加锁操作时,便会阻塞后面对其进行读模式加锁操作的线程。 即当读写锁感知到有线程想要获得写状态锁时,便会阻塞其后所有想要获得读状态锁的线程。这样当读模式的锁解锁后,要获得写状态锁的线程能够访问此锁保护的资源。所以读写锁非常适合资源的读操作远多于写操作的情况。
1)多个读者可以同时进行读
2)写者必须互斥(只允许一个写者写,也不能读者写者同时进行)
3)写者优先于读者(一旦有写者,则后续读者必须等待,唤醒时优先考虑写者)
互斥锁特点:
在访问共享资源之前对进行加锁操作,在访问完成之后进行解锁操作。 加锁后,任何其他试图再次加锁的线程会被阻塞,直到当前线程解锁。 如果解锁时有一个以上的线程阻塞,那么所有该锁上的线程都被编程就绪状态, 第一个变为就绪状态的线程又执行加锁操作,那么其他的线程又会进入等待。 在这种方式下,只有一个线程能够访问被互斥锁保护的资源。
一次只能一个线程拥有互斥锁,其他线程只有等待
自旋锁特点:
自旋锁是一种特殊的互斥锁,当资源被枷锁后,其他线程想要再次加锁,此时该线程不会被阻塞睡眠而是陷入循环等待状态(CPU不能做其它事情),循环检查资源持有者是否已经释放了资源,这样做的好处是减少了线程从睡眠到唤醒的资源消耗,但会一直占用CPU的资源。适用于资源的锁被持有的时间短,而又不希望在线程的唤醒上花费太多资源的情况。
从 实现原理上来讲,互斥锁属于sleep-waiting(睡眠等待)类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和 Core1上。
假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞 (blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。
而自旋锁则不然,它属于busy-waiting(忙等待)类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)