结构体:将不同类型的数据组合成一个整体,是自定义类型; 共同体:不同类型的几个变量共同占用一段内存
1)结构体中的每个成员都有自己独立的地址,它们是同时存在的; 共同体中的所有成员占用同一段内存,它们不能同时存在;
2)sizeof(struct)是内存对齐后所有成员长度的总和,sizeof(union)是内存对齐后最长数据成员的长度
elections.emplace_back("Nelson Mandela", "South Africa", 1994); // 传入的是 创建这个对象 需要的 构造参数
elections.push_back(President("Franklin Delano Roosevelt", "the USA", 1936)); // 传入的是一个对象
elections.emplace_back(President("Franklin Delano Roosevelt", "the USA", 1936)); // 同上一样
1)开放定址法(再散列):当发生地址冲突时,按照某种探测方法继续探测哈希表中的其他存储单元,直到找到空位置为止。
(1)线性探测:按递增顺序,在原来哈希值的基础上往后加一个单位,直至不发生哈希冲突。
(2)再平方探测:在原来哈希值的基础上先加1的平方个单位,若仍然存在则减1的平方个单位。随之是2的平方,3的平方等等。直至不发生哈希冲突。
(3)伪随机探测:通过随机函数随机生成一个数,在原来哈希值的基础上加上随机数,直至不发生哈希冲突。
2)再哈希法:对于冲突的哈希值再次用一个不同哈希函数进行哈希处理,直至没有哈希冲突。不易产生聚集,但是增加计算时间,同时需要准备许多哈希函数。
3)链地址法(拉链法):对于相同的哈希值,使用链表进行连接,再将链表的头指针存放在哈希表的对应单元中。拉链法处理冲突简单,且无堆积现象,不要求表长大于关键字数量,关键字多的情况节省空间,适用于经常进行插入和删除的情况。
4)公共溢出区:将哈希表分为公共表和溢出表两部分,凡是发生冲突的元素,一律填入溢出表。
哈希函数(散列函数)
查询性能:
(1)定义用来将一个标识符定义为一个字符串或常量,注意与const的区别
(2)定义预处理器变量
(3)定义条件编译
(4)定义宏函数,
宏函数在**预处理**时,同函数定义的代码来替换函数名,将函数代码段嵌入到当前程序,不会产生函数调用,所以会省去普通函数保留现场恢复现场的时间,但因为要将定义的函数体嵌入到当前程序,所以不可避免的会占用额外的存储空间
与inline函数的区别:
**内联函数**的作用主要就是使用在一些短小而使用非常频繁的函数中,在调用内联函数的地方将内联函数内的语句Copy到调用函数的地方,从而提高了效率,减少函数调用的开销。比如内联函数inline int func(int x){return x\*x;} 在调用的时候cout<<func(x)<<endl,在编译时将被展开为:cout<<(x\*x)<<endl;
防止申请的动态内存没有被正确释放,导致内存泄漏。
智能指针可以自动释放new分配的内存,不需要手动delete这些new分配的内存
智能指针的实质是一个对象,行为却表现的像一个指针
auto_ptr:c++98版本,在c++11中已不再使用,管理权转移的思想,若通过拷贝构造和赋值操作符赋值它们,原指针会变成null ,而 复制所得的指针将取得资源的唯一控制权。
unique_ptr:c++11版本,独占对所指对象的独有权,不允许其他的智能指针共享其内部的指针,禁止进行拷贝构造和拷贝赋值的操作,但是unique_ptr允许通过函数返回给其他的unique_ptr,还可以通过std::move来把所有权转让到其他的unique_ptr,注意,这时它本身就不再拥有原来指针的所有权了。将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做
//所有权的变化
int *p_i = u_i2.release(); //释放所有权,而不会释放内存的
unique_ptr<string> u_s(new string("abc"));
unique_ptr<string> u_s2 = std::move(u_s); //所有权转移(通过移动语义),u_s所有权转移后,变成“空指针”
u_s2.reset(u_s.release()); //所有权转移
u_s2=nullptr;//显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价
shared_ptr:允许多个指针指向同一个对象,通过引用计数的方式来实现多个shared_ptr对象之间的资源共享。
注意:
shared_ptr内部维护了一个引用计数变量,该变量是指针类型int*,只有指针类型才能保证拷贝自同一对象的不同对象享有相同的引用计数变量。
当对象被销毁时,会将对象的引用计数减一
当引用计数为0时,释放所申请的资源;不为0就不释放
循环引用的问题
class AA{
public:
shared_ptr<BB> bptr;
~A(){cout<<"~A()"<<endl;}
}
class BB
{
public:
shared_ptr<AA> aptr;
~B( ){cout<<"~BB()"<<endl;}
}
int main() {
shared_ptr<AA> aa(new AA());
shared_ptr<BB> bb(new BB());
aa->bptr = bb;
bb->aptr = aa;
return 0;
}
即A内部有指向B,B内部有指向A,这样对于A,B必定是在A析构后B才析构,对于B,A必定是B析构后才析构A,这就是循环引用的问题,违反常规,导致内存泄露。
解决方法:weak_ptr的辅助类,配合shared_ptr而引入,是一种弱引用,指向shared_ptr所管理的对象,在weak_ptr类中不提供引用计数机制,仅起指针的作用,观测资源的使用情况。
class AA
{
public:
weak_ptr<BB> bptr;
~AA( ){cout<<"~AA()"<<endl; }
};
class BB
{
public:
weak_ptr<AA> aptr;
~BB(){cout<<"~BB()"<<endl; }
};
int main( ) {
shared_ptr<AA> aa(new AA());
shared_ptr<BB> bb(new BB());
aa->bptr = bb;
bb->aptr = aa;
cout<<aa.use_count()<<endl;
cout<<bb.use_count()<<endl;
return 0;
}
就是一个动态数组,里面有一个指针指向一片连续的内存空间。
特点:内存空间只会增长不会减少
作为C++ STL关系式容器(如set,multiset,map, multimap)的底层实现。
红黑树可以在O(log n)时间内做查找,插入和删除
(1)序列式容器
顺序访问元素的容器,vector、list(双向链表)、deque(双端队列)
vector:底层数据结构:数组
(2)关联式容器
无序关联容器
按键值排好序,底层数据结构均为红黑树
set,multiset,map, multimap,元素是否唯一的区别
无序关联容器
从C++11开始提供的容器,无序的容器,unordered_map、unordered_multimap、unordered_set、unordered_mutiset
底层数据结构为哈希表,解决冲突的策略使用的是拉链法,通过在不同桶中新建节点的方式来避免冲突
(3)容器适配器
在上述容器的接口上进行封装和改写实现
底层容器:deque
底层容器:deque
底层容器:vector实现的Heap
STL提供了六大组件,彼此之间可以组合套用,这六大组件分别是:容器、算法、迭代器、仿函数、适配器、空间配置器。
对于STL中的set和map来说,需要进行频繁的插入和删除
AVL是一种严格平衡二叉树,因此在增加或者删除节点的时候,旋转的次数比红黑树要多,影响性能,只适合查找较多但插入、删除不多的操作。当然,由于AVL高度平衡,因此AVL的Search效率更高啦。
红黑树也是一种平衡二叉树,但不追求"完全平衡",它只要求部分达到平衡
在增删节点时候旋转次数会降低,任何不平衡都会在三次旋转之内解决,因此,更适合插入、删除操作较多的结构。
红黑树,读取略逊于AVL,维护强于AVL,综合来看更适合STL场景。
DDos全名Distributed Denial of Service,翻译成中文就是分布式拒绝服务。指的是处于不同位置的多个攻击者同时向一个或数个目标发动攻击,是一种分布的、协同的大规模攻击方式。单一的DoS攻击一般是采用一对一方式的,它利用网络协议和操作系统的一些缺陷,采用欺骗和伪装的策略来进行网络攻击,它在短时间内发起大量请求,使网站服务器充斥大量要求回复的信息,消耗网络带宽或系统资源,导致网络或系统不胜负荷以至于瘫痪而停止提供正常的网络服务
# SYN Flood进行DDoS攻击的实现原理 SYN Flood是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。
一次正常的建立TCP连接,需要三次握手:客户端发送SYN报文,服务端收到请求并返回报文表示接受,客户端也返回确认,完成连接。
SYN Flood 就是用户向服务器发送报文后突然死机或掉线,那么服务器在发出应答报文后就无法收到客户端的确认报文(第三次握手无法完成),这时服务器端一般会重试并等待一段时间后再丢弃这个未完成的连接。
一个用户出现异常导致服务器的一个线程等待一会儿并不是大问题,但恶意攻击者大量模拟这种情况,服务器端为了维护数以万计的半连接而消耗非常多的资源,结果往往是无暇理睬客户的正常请求,甚至崩溃。从正常客户的角度看来,网站失去了响应,无法访问。
如何防范?
1、防火墙
2、充足的网络带宽保证
3、CDN
CDN 指的是网站的静态内容分发到多个服务器,用户就近访问,提高速度。因此,CDN 也是带宽扩容的一种方法,可以用来防御 DDOS 攻击。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。