Merge pull request #15 from huihut/master

归并排序空间复杂度有误
This commit is contained in:
Menghui Xie 2018-09-17 08:21:53 -04:00 committed by GitHub
commit 71605ec3d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1660 additions and 225 deletions

View File

@ -0,0 +1,25 @@
//
// Created by xiemenghui on 2018/7/20.
//
#include "Factory.h"
#include "concrete_factory.h"
Factory* Factory::CreateFactory(FACTORY_TYPE factory)
{
Factory *pFactory = nullptr;
switch (factory) {
case FACTORY_TYPE::BENZ_FACTORY: // 奔驰工厂
pFactory = new BenzFactory();
break;
case FACTORY_TYPE::BMW_FACTORY: // 宝马工厂
pFactory = new BmwFactory();
break;
case FACTORY_TYPE::AUDI_FACTORY: // 奥迪工厂
pFactory = new AudiFactory();
break;
default:
break;
}
return pFactory;
}

View File

@ -0,0 +1,24 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_FACTORY_H
#define DESIGNPATTERN_FACTORY_H
#include "product.h"
// 抽象工厂模式
class Factory {
public:
enum FACTORY_TYPE {
BENZ_FACTORY, // 奔驰工厂
BMW_FACTORY, // 宝马工厂
AUDI_FACTORY // 奥迪工厂
};
virtual ICar* CreateCar() = 0; // 生产汽车
virtual IBike* CreateBike() = 0; // 生产自行车
static Factory * CreateFactory(FACTORY_TYPE factory); // 创建工厂
};
#endif //DESIGNPATTERN_FACTORY_H

View File

@ -0,0 +1,46 @@
//
// Created by xiemenghui on 2018/7/20.
//
#include "Factory.h"
#include "product.h"
#include "FactoryMain.h"
#include <iostream>
using namespace std;
void FactoryMain()
{
// ąźłŰ
Factory * pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BENZ_FACTORY);
ICar * pCar = pFactory->CreateCar();
IBike * pBike = pFactory->CreateBike();
cout << "Benz factory - Car: " << pCar->Name() << endl;
cout << "Benz factory - Bike: " << pBike->Name() << endl;
SAFE_DELETE(pCar);
SAFE_DELETE(pBike);
SAFE_DELETE(pFactory);
// ąŚÂí
pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::BMW_FACTORY);
pCar = pFactory->CreateCar();
pBike = pFactory->CreateBike();
cout << "Bmw factory - Car: " << pCar->Name() << endl;
cout << "Bmw factory - Bike: " << pBike->Name() << endl;
SAFE_DELETE(pCar);
SAFE_DELETE(pBike);
SAFE_DELETE(pFactory);
// °ÂľĎ
pFactory = Factory::CreateFactory(Factory::FACTORY_TYPE::AUDI_FACTORY);
pCar = pFactory->CreateCar();
pBike = pFactory->CreateBike();
cout << "Audi factory - Car: " << pCar->Name() << endl;
cout << "Audi factory - Bike: " << pBike->Name() << endl;
SAFE_DELETE(pCar);
SAFE_DELETE(pBike);
SAFE_DELETE(pFactory);
}

View File

@ -0,0 +1,14 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_FACTORYMAIN_H
#define DESIGNPATTERN_FACTORYMAIN_H
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p) {delete(p); (p)=nullptr;}}
#endif
void FactoryMain();
#endif //DESIGNPATTERN_FACTORYMAIN_H

View File

@ -0,0 +1,51 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_CONCRETE_FACTORY_H
#define DESIGNPATTERN_CONCRETE_FACTORY_H
#include "Factory.h"
#include "concrete_product.h"
// 奔驰工厂
class BenzFactory : public Factory
{
public:
ICar* CreateCar()
{
return new BenzCar();
}
IBike* CreateBike()
{
return new BenzBike();
}
};
// 宝马工厂
class BmwFactory : public Factory
{
public:
ICar* CreateCar() {
return new BmwCar();
}
IBike* CreateBike() {
return new BmwBike();
}
};
// 奥迪工厂
class AudiFactory : public Factory
{
public:
ICar* CreateCar() {
return new AudiCar();
}
IBike* CreateBike() {
return new AudiBike();
}
};
#endif //DESIGNPATTERN_CONCRETE_FACTORY_H

View File

@ -0,0 +1,72 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_CONCRETE_PRODUCT_H
#define DESIGNPATTERN_CONCRETE_PRODUCT_H
#include "product.h"
/********** 汽车 **********/
// 奔驰
class BenzCar : public ICar
{
public:
string Name()
{
return "Benz Car";
}
};
// 宝马
class BmwCar : public ICar
{
public:
string Name()
{
return "Bmw Car";
}
};
// 奥迪
class AudiCar : public ICar
{
public:
string Name()
{
return "Audi Car";
}
};
/********** 自行车 **********/
// 奔驰
class BenzBike : public IBike
{
public:
string Name()
{
return "Benz Bike";
}
};
// 宝马
class BmwBike : public IBike
{
public:
string Name()
{
return "Bmw Bike";
}
};
// 奥迪
class AudiBike : public IBike
{
public:
string Name()
{
return "Audi Bike";
}
};
#endif //DESIGNPATTERN_CONCRETE_PRODUCT_H

View File

@ -0,0 +1,25 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_PRODUCT_H
#define DESIGNPATTERN_PRODUCT_H
#include <string>
using std::string;
// 汽车接口
class ICar
{
public:
virtual string Name() = 0;
};
// 自行车接口
class IBike
{
public:
virtual string Name() = 0;
};
#endif //DESIGNPATTERN_PRODUCT_H

View File

@ -0,0 +1,21 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_ADAPTERMAIN_H
#define DESIGNPATTERN_ADAPTERMAIN_H
#include "adapter.h"
void AdapterMain()
{
// 创建适配器
IRussiaSocket * pAdapter = new PowerAdapter();
// 充电
pAdapter->Charge();
SAFE_DELETE(pAdapter);
}
#endif //DESIGNPATTERN_ADAPTERMAIN_H

View File

@ -0,0 +1,20 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_ADAPTEE_H
#define DESIGNPATTERN_ADAPTEE_H
#include <iostream>
// 自带的充电器(两脚扁型)
class OwnCharger
{
public:
void ChargeWithFeetFlat()
{
std::cout << "OwnCharger::ChargeWithFeetFlat\n";
}
};
#endif //DESIGNPATTERN_ADAPTEE_H

View File

@ -0,0 +1,34 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_ADAPTER_H
#define DESIGNPATTERN_ADAPTER_H
#include "target.h"
#include "adaptee.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif
// 电源适配器
class PowerAdapter : public IRussiaSocket
{
public:
PowerAdapter() : m_pCharger(new OwnCharger()){}
~PowerAdapter()
{
SAFE_DELETE(m_pCharger);
}
void Charge()
{
// 使用自带的充电器(两脚扁形)充电
m_pCharger->ChargeWithFeetFlat();
}
private:
// 持有需要被适配的接口对象(自带的充电器)
OwnCharger* m_pCharger;
};
#endif //DESIGNPATTERN_ADAPTER_H

View File

@ -0,0 +1,16 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_TARGET_H
#define DESIGNPATTERN_TARGET_H
// 俄罗斯提供的插座
class IRussiaSocket
{
public:
// 使用双脚圆形充电(暂不实现)
virtual void Charge() = 0;
};
#endif //DESIGNPATTERN_TARGET_H

View File

@ -0,0 +1,30 @@
//
// Created by xiemenghui on 2018/7/21.
//
#include "BridgeMain.h"
void BridgeMain()
{
// 创建电器(电灯、电风扇)
IElectricalEquipment * light = new Light();
IElectricalEquipment * fan = new Fan();
// 创建开关(拉链式开关、两位开关)
// 将拉链式开关和电灯关联起来,两位开关和风扇关联起来
ISwitch * pullChain = new PullChainSwitch(light);
ISwitch * twoPosition = new TwoPositionSwitch(fan);
// 开灯、关灯
pullChain->On();
pullChain->Off();
// 打开风扇、关闭风扇
twoPosition->On();
twoPosition->Off();
SAFE_DELETE(twoPosition);
SAFE_DELETE(pullChain);
SAFE_DELETE(fan);
SAFE_DELETE(light);
}

View File

@ -0,0 +1,17 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_BRIDGEMAIN_H
#define DESIGNPATTERN_BRIDGEMAIN_H
#include "refined_abstraction.h"
#include "concrete_implementor.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} }
#endif
void BridgeMain();
#endif //DESIGNPATTERN_BRIDGEMAIN_H

View File

@ -0,0 +1,23 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_ABSTRACTION_H
#define DESIGNPATTERN_ABSTRACTION_H
#include "implementor.h"
// 开关
class ISwitch
{
public:
ISwitch(IElectricalEquipment *ee){ m_pEe = ee; }
virtual ~ISwitch(){}
virtual void On() = 0; // 打开电器
virtual void Off() = 0; // 关闭电器
protected:
IElectricalEquipment * m_pEe;
};
#endif //DESIGNPATTERN_ABSTRACTION_H

View File

@ -0,0 +1,44 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H
#define DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H
#include "implementor.h"
#include <iostream>
// 电灯
class Light : public IElectricalEquipment
{
public:
// 开灯
virtual void PowerOn() override
{
std::cout << "Light is on." << std::endl;
}
// 关灯
virtual void PowerOff() override
{
std::cout << "Light is off." << std::endl;
}
};
// 风扇
class Fan : public IElectricalEquipment
{
public:
// 打开风扇
virtual void PowerOn() override
{
std::cout << "Fan is on." << std::endl;
}
//关闭风扇
virtual void PowerOff() override
{
std::cout << "Fan is off." << std::endl;
}
};
#endif //DESIGNPATTERN_CONCRETE_IMPLEMENTOR_H

View File

@ -0,0 +1,17 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_IMPLEMENTOR_H
#define DESIGNPATTERN_IMPLEMENTOR_H
// 电器
class IElectricalEquipment
{
public:
virtual ~IElectricalEquipment(){}
virtual void PowerOn() = 0; // 打开
virtual void PowerOff() = 0; // 关闭
};
#endif //DESIGNPATTERN_IMPLEMENTOR_H

View File

@ -0,0 +1,53 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_REFINED_ABSTRACTION_H
#define DESIGNPATTERN_REFINED_ABSTRACTION_H
#include "abstraction.h"
#include <iostream>
// 拉链式开关
class PullChainSwitch : public ISwitch
{
public:
PullChainSwitch(IElectricalEquipment *ee) : ISwitch(ee) {}
// 用拉链式开关打开电器
virtual void On() override
{
std::cout << "Switch on the equipment with a pull chain switch." << std::endl;
m_pEe->PowerOn();
}
// 用拉链式开关关闭电器
virtual void Off() override
{
std::cout << "Switch off the equipment with a pull chain switch." << std::endl;
m_pEe->PowerOff();
}
};
// 两位开关
class TwoPositionSwitch : public ISwitch
{
public:
TwoPositionSwitch(IElectricalEquipment *ee) : ISwitch(ee) {}
// 用两位开关打开电器
virtual void On() override
{
std::cout << "Switch on the equipment with a two-position switch." << std::endl;
m_pEe->PowerOn();
}
// 用两位开关关闭电器
virtual void Off() override {
std::cout << "Switch off the equipment with a two-position switch." << std::endl;
m_pEe->PowerOff();
}
};
#endif //DESIGNPATTERN_REFINED_ABSTRACTION_H

View File

@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.10)
project(DesignPattern)
set(CMAKE_CXX_STANDARD 11)
add_executable(DesignPattern main.cpp AbstractFactoryPattern/product.h AbstractFactoryPattern/concrete_product.h AbstractFactoryPattern/Factory.cpp AbstractFactoryPattern/Factory.h AbstractFactoryPattern/concrete_factory.h AbstractFactoryPattern/FactoryMain.cpp AbstractFactoryPattern/FactoryMain.h SingletonPattern/Singleton.cpp SingletonPattern/Singleton.h SingletonPattern/SingletonMain.h AdapterPattern/target.h AdapterPattern/adaptee.h AdapterPattern/adapter.h AdapterPattern/AdapterMain.h BridgePattern/implementor.h BridgePattern/concrete_implementor.h BridgePattern/abstraction.h BridgePattern/refined_abstraction.h BridgePattern/BridgeMain.h BridgePattern/BridgeMain.cpp ObserverPattern/subject.h ObserverPattern/observer.h ObserverPattern/concrete_subject.h ObserverPattern/concrete_observer.h ObserverPattern/ObserverMain.cpp ObserverPattern/ObserverMain.h)

View File

@ -0,0 +1,34 @@
//
// Created by xiemenghui on 2018/7/21.
//
#include "ObserverMain.h"
void ObserverMain()
{
// 创建主题
ConcreteSubject * pSubject = new ConcreteSubject();
// 创建观察者
IObserver * pObserver1 = new ConcreteObserver("Jack Ma");
IObserver * pObserver2 = new ConcreteObserver("Pony");
// 注册观察者
pSubject->Attach(pObserver1);
pSubject->Attach(pObserver2);
// 更改价格,并通知观察者
pSubject->SetPrice(12.5);
pSubject->Notify();
// 注销一个观察者
pSubject->Detach(pObserver2);
// 再次更改状态,并通知观察者
pSubject->SetPrice(15.0);
pSubject->Notify();
SAFE_DELETE(pObserver1);
SAFE_DELETE(pObserver2);
SAFE_DELETE(pSubject);
}

View File

@ -0,0 +1,17 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_OBSERVERMAIN_H
#define DESIGNPATTERN_OBSERVERMAIN_H
#include "concrete_subject.h"
#include "concrete_observer.h"
#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=nullptr;} }
#endif
void ObserverMain();
#endif //DESIGNPATTERN_OBSERVERMAIN_H

View File

@ -0,0 +1,25 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_CONCRETE_OBSERVER_H
#define DESIGNPATTERN_CONCRETE_OBSERVER_H
#include "observer.h"
#include <iostream>
#include <string>
class ConcreteObserver : public IObserver
{
public:
ConcreteObserver(std::string name) { m_strName = name; }
void Update(float price)
{
std::cout << m_strName << " - price" << price << "\n";
}
private:
std::string m_strName; // 名字
};
#endif //DESIGNPATTERN_CONCRETE_OBSERVER_H

View File

@ -0,0 +1,45 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_CONCRETE_SUBJECT_H
#define DESIGNPATTERN_CONCRETE_SUBJECT_H
#include "subject.h"
#include "observer.h"
#include <iostream>
#include <list>
// 具体主题
class ConcreteSubject : public ISubject
{
public:
ConcreteSubject(){ m_fPrice = 10.0; }
void SetPrice(float price)
{
m_fPrice = price;
}
void Attach(IObserver * observer)
{
m_observers.push_back(observer);
}
void Detach(IObserver * observer)
{
m_observers.remove(observer);
}
// 通知所有观察者
void Notify()
{
std::list<IObserver *>::iterator it = m_observers.begin();
while (it != m_observers.end())
{
(*it)->Update(m_fPrice);
++it;
}
}
private:
std::list<IObserver *> m_observers; // 观察者列表
float m_fPrice; // 价格
};
#endif //DESIGNPATTERN_CONCRETE_SUBJECT_H

View File

@ -0,0 +1,15 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_OBSERVER_H
#define DESIGNPATTERN_OBSERVER_H
// 抽象观察者
class IObserver
{
public:
virtual void Update(float price) = 0; // 更新价格
};
#endif //DESIGNPATTERN_OBSERVER_H

View File

@ -0,0 +1,18 @@
//
// Created by xiemenghui on 2018/7/21.
//
#ifndef DESIGNPATTERN_SUBJECT_H
#define DESIGNPATTERN_SUBJECT_H
class IObserver;
class ISubject
{
public:
virtual void Attach(IObserver *) = 0; // 注册观察者
virtual void Detach(IObserver *) = 0; // 注销观察者
virtual void Notify() = 0; // 通知观察者
};
#endif //DESIGNPATTERN_SUBJECT_H

11
DesignPattern/README.md Normal file
View File

@ -0,0 +1,11 @@
# 设计模式
> 各大设计模式例子参考:[CSDN专栏 . C++ 设计模式](https://blog.csdn.net/column/details/15392.html) 系列博文
此文件夹为一个 CLion 工程,由 CMake 构建,各个文件夹为各个设计模式的具体实现。文件中可能会有中文乱码问题,请以 `GB2312`(中文) 编码打开。
* [单例模式例子](SingletonPattern)
* [抽象工厂模式例子](AbstractFactoryPattern)
* [适配器模式例子](AdapterPattern)
* [桥接模式例子](BridgePattern)
* [观察者模式例子](ObserverPattern)

View File

@ -0,0 +1,34 @@
# 单例模式
```cpp
// 懒汉式单例模式
class Singleton
{
private:
Singleton() { }
static Singleton * pInstance;
public:
static Singleton * GetInstance()
{
if (pInstance == nullptr)
pInstance = new Singleton();
return pInstance;
}
};
// 线程安全的单例模式
class Singleton
{
private:
Singleton() { }
~Singleton() { }
Singleton(const Singleton &);
Singleton & operator = (const Singleton &);
public:
static Singleton & GetInstance()
{
static Singleton instance;
return instance;
}
};
```

View File

@ -0,0 +1,11 @@
//
// Created by xiemenghui on 2018/7/20.
//
#include <iostream>
#include "Singleton.h"
void Singleton::DoSomething()
{
std::cout << "Singleton do something\n";
}

View File

@ -0,0 +1,25 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_SINGLETON_H
#define DESIGNPATTERN_SINGLETON_H
// 单例模式
class Singleton {
private:
Singleton(){}
~Singleton(){}
Singleton(const Singleton &);
Singleton & operator= (const Singleton &);
public:
static Singleton & GetInstance()
{
static Singleton instance;
return instance;
}
void DoSomething();
};
#endif //DESIGNPATTERN_SINGLETON_H

View File

@ -0,0 +1,15 @@
//
// Created by xiemenghui on 2018/7/20.
//
#ifndef DESIGNPATTERN_SINGLETONMAIN_H
#define DESIGNPATTERN_SINGLETONMAIN_H
#include "Singleton.h"
void SingletonMain()
{
Singleton::GetInstance().DoSomething();
}
#endif //DESIGNPATTERN_SINGLETONMAIN_H

43
DesignPattern/main.cpp Normal file
View File

@ -0,0 +1,43 @@
//
// Created by xiemenghui on 2018/7/20.
//
#include <iostream>
#include "SingletonPattern/SingletonMain.h"
#include "AbstractFactoryPattern/FactoryMain.h"
#include "AdapterPattern/AdapterMain.h"
#include "BridgePattern/BridgeMain.h"
#include "ObserverPattern/ObserverMain.h"
int main() {
std::cout << "*******************" << std::endl;
std::cout << "** Éè¼ÆģʽÀý×Ó **" << std::endl;
std::cout << "*******************" << std::endl;
std::cout << "*******************" << std::endl;
std::cout << "** µ¥Àýģʽ **" << std::endl;
std::cout << "*******************" << std::endl;
SingletonMain();
std::cout << "*******************" << std::endl;
std::cout << "** ³éÏ󹤳§Ä£Ê½ **" << std::endl;
std::cout << "*******************" << std::endl;
FactoryMain();
std::cout << "*******************" << std::endl;
std::cout << "** ÊÊÅäÆ÷ģʽ **" << std::endl;
std::cout << "*******************" << std::endl;
AdapterMain();
std::cout << "*******************" << std::endl;
std::cout << "** ÇŽÓģʽ **" << std::endl;
std::cout << "*******************" << std::endl;
BridgeMain();
std::cout << "*******************" << std::endl;
std::cout << "** ¹Û²ìÕßģʽ **" << std::endl;
std::cout << "*******************" << std::endl;
ObserverMain();
return 0;
}

778
README.md
View File

@ -1,6 +1,8 @@
# C/C++ 面试知识总结
为 2018 年春招总结的 C/C++ 面试知识,只为复习、分享。部分知识点与图片来自网络,侵删。欢迎 star欢迎 issues。
C/C++ 面试知识总结,只为复习、分享。部分知识点与图片来自网络,侵删。
勘误请 Issue、Pull新增请 Issue建议、讨论请 [# issues/12](https://github.com/huihut/interview/issues/12)
## 使用建议
@ -91,17 +93,6 @@ int* const function7(); // 返回一个指向变量的常指针使用i
</details>
### volatile
```cpp
volatile int i = 10;
```
* volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。
* volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值)
* const 可以是 volatile (如只读的状态寄存器)
* 指针可以是 volatile
### static
#### 作用
@ -113,7 +104,7 @@ volatile int i = 10;
### this 指针
1. `this` 指针是一个隐含于每一个成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。
1. `this` 指针是一个隐含于每一个非静态成员函数中的特殊指针。它指向正在被该成员函数操作的那个对象。
2. 当对一个对象调用成员函数时,编译程序先将对象的地址赋给 `this` 指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含使用 `this` 指针。
3. 当一个成员函数被调用时,自动向它传递一个隐含的参数,该参数是一个指向这个成员函数所在的对象的指针。
4. `this` 指针被隐含地声明为: `ClassName *const this`,这意味着不能给 `this` 指针赋值;在 `ClassName` 类的 `const` 成员函数中,`this` 指针的类型为:`const ClassName* const`,这说明不能对 `this` 指针所指向的这种对象是不可修改的(即不能对这种对象的数据成员进行赋值操作);
@ -151,7 +142,7 @@ inline int functionName(int first, int secend,...) {/****/};
</details>
#### 编译器对inline函数的处理步骤
#### 编译器对 inline 函数的处理步骤
1. 将 inline 函数体复制到 inline 函数调用点处;
2. 为所用 inline 函数中的局部变量分配内存空间;
@ -228,9 +219,7 @@ int main()
### assert()
断言是宏而非函数。assert 宏的原型定义在`<assert.h>`C、`<cassert>`C++)中,其作用是如果它的条件返回错误,则终止程序执行。
断言是宏而非函数。assert 宏的原型定义在`<assert.h>`C、`<cassert>`C++)中,其作用是如果它的条件返回错误,则终止程序执行。如:
```cpp
assert( p != NULL );
@ -264,6 +253,29 @@ struct test
</details>
### 位域
```cpp
Bit mode: 2; // mode 占 2 位
```
类可以将其非静态数据成员定义为位域bit-field在一个位域中含有一定数量的二进制位。当一个程序需要向其他程序或硬件设备传递二进制数据时通常会用到位域。
* 位域在内存中的布局是与机器有关的
* 位域的类型必须是整型或枚举类型,带符号类型中的位域的行为将因具体实现而定
* 取地址运算符(&)不能作用于位域,任何指针都无法指向类的位域
### volatile
```cpp
volatile int i = 10;
```
* volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素(操作系统、硬件、其它线程等)更改。所以使用 volatile 告诉编译器不应对这样的对象进行优化。
* volatile 关键字声明的变量,每次访问时都必须从内存中取出值(没有被 volatile 修饰的变量,可能由于编译器的优化,从 CPU 寄存器中取值)
* const 可以是 volatile (如只读的状态寄存器)
* 指针可以是 volatile
### extern "C"
* 被 extern 限定的函数或变量是 extern 类型的
@ -358,6 +370,57 @@ int main() {
1. 默认的继承访问权限。struct 是 public 的class 是 private 的。
2. struct 作为数据结构的实现体,它默认的数据访问控制是 public 的,而 class 作为对象的实现体,它默认的成员变量访问控制是 private 的。
### union 联合
联合union是一种节省空间的特殊的类一个 union 可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当某个成员被赋值后其他成员变为未定义状态。联合有如下特点:
* 默认访问控制符为 public
* 可以含有构造函数、析构函数
* 不能含有引用类型的成员
* 不能继承自其他类,不能作为基类
* 不能含有虚函数
* 匿名 union 在定义所在作用域可直接访问 union 成员
* 匿名 union 不能包含 protected 成员或 private 成员
* 全局匿名联合必须是静态static
<details><summary>union 使用</summary>
```cpp
#include<iostream>
union UnionTest {
UnionTest() : i(10) {};
int i;
double d;
};
static union {
int i;
double d;
};
int main() {
UnionTest u;
union {
int i;
double d;
};
std::cout << u.i << std::endl; // 输出 UnionTest 联合的 10
::i = 20;
std::cout << ::i << std::endl; // 输出全局静态匿名联合的 20
i = 30;
std::cout << i << std::endl; // 输出局部匿名联合的 30
return 0;
}
```
</details>
### C 实现 C++ 类
[C 语言实现封装、继承和多态](http://dongxicheng.org/cpp/ooc/)
@ -420,6 +483,24 @@ int main()
using namespace_name::name;
```
#### 构造函数的 using 声明【C++11】
在 C++11 中,派生类能够重用其直接基类定义的构造函数。
```cpp
class Derived : Base {
public:
using Base::Base;
/* ... */
};
```
如上 using 声明,对于基类的每个构造函数,编译器都生成一个与之对应(形参列表完全相同)的派生类构造函数。生成如下类型构造函数:
```cpp
derived(parms) : base(args) { }
```
#### using 指示
`using 指示` 使得某个特定命名空间中所有名字都可见,这样我们就无需再为它们添加任何前缀限定符了。如:
@ -472,17 +553,17 @@ cout << x << endl;
<details><summary>:: 使用</summary>
```cpp
int count = 0; // 全局(::)的 count
int count = 0; // 全局(::)的 count
class A {
public:
static int count; // 类 A 的 countA::count
static int count; // 类 A 的 countA::count
};
int main() {
::count = 1; // 设置全局的 count 的值为 1
A::count = 2; // 设置类 A 的 count 为 2
A::count = 2; // 设置类 A 的 count 为 2
int count = 0; // 局部的 count
count = 3; // 设置局部的 count 的值为 3
@ -493,11 +574,75 @@ int main() {
</details>
### enum 枚举类型
#### 限定作用域的枚举类型
```cpp
enum class open_modes { input, output, append };
```
#### 不限定作用域的枚举类型
```cpp
enum color { red, yellow, green };
enum { floatPrec = 6, doublePrec = 10 };
```
### decltype
decltype 关键字用于检查实体的声明类型或表达式的类型及值分类。语法:
```cpp
decltype ( expression )
```
<details><summary>decltype 使用</summary>
```cpp
// 尾置返回允许我们在参数列表之后声明返回类型
template <typename It>
auto fcn(It beg, It end) -> decltype(*beg)
{
// 处理序列
return *beg; // 返回序列中一个元素的引用
}
// 为了使用模板参数成员,必须用 typename
template <typename It>
auto fcn2(It beg, It end) -> typename remove_reference<decltype(*beg)>::type
{
// 处理序列
return *beg; // 返回序列中一个元素的拷贝
}
```
</details>
### 引用
#### 左值引用
常规引用,一般表示对象的身份。
#### 右值引用
右值引用就是必须绑定到右值(一个临时对象、将要销毁的对象)的引用,一般表示对象的值。
右值引用可实现转移语义Move Sementics和精确传递Perfect Forwarding它的主要目的有两个方面
* 消除两个对象交互时不必要的对象拷贝,节省运算存储资源,提高效率。
* 能够更简洁明确地定义泛型函数。
#### 引用折叠
* `X& &`、`X& &&`、`X&& &` 可折叠成 `X&`
* `X&& &&` 可折叠成 `X&&`
### 宏
* 宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对 “参数” 进行的是一对一的替换。
* 宏定义可以实现类似于函数的功能,但是它终归不是函数,而宏定义中括弧中的“参数”也不是真的参数,在宏展开的时候对 “参数” 进行的是一对一的替换。
### 初始化列表
### 成员初始化列表
好处
@ -507,6 +652,64 @@ int main() {
2. 引用类型,引用必须在定义的时候初始化,并且不能重新赋值,所以也要写在初始化列表里面
3. 没有默认构造函数的类类型,因为使用初始化列表可以不必调用默认构造函数来初始化,而是直接调用拷贝构造函数初始化。
### initializer_list 列表初始化【C++11】
用花括号初始化器列表列表初始化一个对象,其中对应构造函数接受一个 `std::initializer_list` 参数.
<details><summary>initializer_list 使用</summary>
```cpp
#include <iostream>
#include <vector>
#include <initializer_list>
template <class T>
struct S {
std::vector<T> v;
S(std::initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l) {
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const {
return {&v[0], v.size()}; // 在 return 语句中复制列表初始化
// 这不使用 std::initializer_list
}
};
template <typename T>
void templated_fn(T) {}
int main()
{
S<int> s = {1, 2, 3, 4, 5}; // 复制初始化
s.append({6, 7, 8}); // 函数调用中的列表初始化
std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
for (auto n : s.v)
std::cout << n << ' ';
std::cout << '\n';
std::cout << "Range-for over brace-init-list: \n";
for (int x : {-1, -2, -3}) // auto 的规则令此带范围 for 工作
std::cout << x << ' ';
std::cout << '\n';
auto al = {10, 11, 12}; // auto 的特殊规则
std::cout << "The list bound to auto has size() = " << al.size() << '\n';
// templated_fn({1, 2, 3}); // 编译错误!“ {1, 2, 3} ”不是表达式,
// 它无类型,故 T 无法推导
templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
templated_fn<std::vector<int>>({1, 2, 3}); // 也 OK
}
```
</details>
### 面向对象
@ -675,6 +878,11 @@ virtual int A() = 0;
* 虚函数不占用存储空间
* 虚函数表存储的是虚函数地址
### 模板类、成员模板、虚函数
* 模板类中可以使用虚函数
* 一个类(无论是普通类还是类模板)的成员模板(本身是模板的成员函数)不能是虚函数
### 抽象类、接口类、聚合类
* 抽象类:含有纯虚函数的类
@ -718,7 +926,7 @@ p = nullptr;
#### new、delete
1. new/new[]:完成两件事,先底层调用 malloc 分了配内存,然后调用构造函数(创建对象)。
1. new / new[]:完成两件事,先底层调用 malloc 分了配内存,然后调用构造函数(创建对象)。
2. delete/delete[]:也完成两件事,先调用析构函数(清理资源),然后底层调用 free 释放空间。
3. new 在申请内存时会自动计算所需字节数,而 malloc 则需我们自己输入申请内存空间的字节数。
@ -737,6 +945,20 @@ int main()
</details>
#### 定位 new
定位 newplacement new允许我们向 new 传递额外的参数。
```cpp
new (palce_address) type
new (palce_address) type (initializers)
new (palce_address) type [size]
new (palce_address) type [size] { braced initializer list }
```
* `palce_address` 是个指针
* `initializers` 提供一个(可能为空的)以逗号分隔的初始值列表
### delete this 合法吗?
[Is it legal (and moral) for a member function to say delete this?](https://isocpp.org/wiki/faq/freestore-mgmt#delete-this)
@ -1004,11 +1226,6 @@ hash_multiset|hash表|无序|可重复|
hash_map|hash表|无序|不可重复|
hash_multimap|hash表|无序|可重复|
### STL 空间配置器如何处理内存的?能说一下它的大概实现方案吗?为什么是 8Bytes 的倍数?
* 大于 128Bytes 用 malloc 直接申请
* 小于 128Bytes 使用一个 8Bytes 倍数的数组来进行申请(原因是为了提高效率,同时对于 64 位的机器而言,地址大小为 8Bytes
## 数据结构
### 顺序结构
@ -1478,6 +1695,21 @@ typedef struct BiTNode
2-3树 | O(log<sub>2</sub>n - log<sub>3</sub>n) | |
B树/B+树 |O(log<sub>2</sub>n) | |
### 图搜索算法
图搜索算法 |数据结构| 遍历时间复杂度 | 空间复杂度
---|---|---|---
[BFS广度优先搜索](https://zh.wikipedia.org/wiki/%E5%B9%BF%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2)|邻接矩阵<br/>邻接链表|O(\|v\|<sup>2</sup>)<br/>O(\|v\|+\|E\|)|O(\|v\|<sup>2</sup>)<br/>O(\|v\|+\|E\|)
[DFS深度优先搜索](https://zh.wikipedia.org/wiki/%E6%B7%B1%E5%BA%A6%E4%BC%98%E5%85%88%E6%90%9C%E7%B4%A2)|邻接矩阵<br/>邻接链表|O(\|v\|<sup>2</sup>)<br/>O(\|v\|+\|E\|)|O(\|v\|<sup>2</sup>)<br/>O(\|v\|+\|E\|)
### 其他算法
算法 |思想| 应用
---|---|---
[分治法](https://zh.wikipedia.org/wiki/%E5%88%86%E6%B2%BB%E6%B3%95)|把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并|[循环赛日程安排问题](https://github.com/huihut/interview/tree/master/Problems/RoundRobinProblem)、排序算法(快速排序、归并排序)
[动态规划](https://zh.wikipedia.org/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92)|通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法,适用于有重叠子问题和最优子结构性质的问题|[背包问题](https://github.com/huihut/interview/tree/master/Problems/KnapsackProblem)、斐波那契数列
[贪心法](https://zh.wikipedia.org/wiki/%E8%B4%AA%E5%BF%83%E6%B3%95)|一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法|旅行推销员问题(最短路径问题)、最小生成树、哈夫曼编码
## Problems
### Single Problem
@ -1962,6 +2194,41 @@ TCP 是一个基于字节流的传输服务UDP 基于报文的),“流”
* 在数据包之间设置边界,如添加特殊符号 `\r\n` 标记。FTP 协议正是这么做的。但问题在于如果数据正文中也含有 `\r\n`,则会误判为消息的边界。
* 使用更加复杂的应用层协议。
#### TCP 流量控制
##### 概念
流量控制flow control就是让发送方的发送速率不要太快要让接收方来得及接收。
##### 方法
<details><summary>利用可变窗口进行流量控制</summary>
![](images/利用可变窗口进行流量控制举例.png)
</details>
#### TCP 拥塞控制
##### 概念
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。
##### 方法
* 慢开始( slow-start )
* 拥塞避免( congestion avoidance )
* 快重传( fast retransmit )
* 快恢复( fast recovery )
<details><summary>TCP的拥塞控制图</summary>
![](images/TCP拥塞窗口cwnd在拥塞控制时的变化情况.png)
![](images/快重传示意图.png)
![](images/TCP的拥塞控制流程图.png)
</details>
#### TCP 传输连接管理
> 因为 TCP 三次握手建立连接、四次挥手释放连接很重要,所以附上《计算机网络(第 7 版)-谢希仁》书中对此章的详细描述:<https://github.com/huihut/interview/blob/master/images/TCP-transport-connection-management.png>
@ -2200,6 +2467,30 @@ ssize_t write(int fd, const void *buf, size_t count);
## 设计模式
> 各大设计模式例子参考:[CSDN专栏 . C++ 设计模式](https://blog.csdn.net/column/details/15392.html) 系列博文
[设计模式工程目录](DesignPattern)
### 单例模式
[单例模式例子](DesignPattern/SingletonPattern)
### 抽象工厂模式
[抽象工厂模式例子](DesignPattern/AbstractFactoryPattern)
### 适配器模式
[适配器模式例子](DesignPattern/AdapterPattern)
### 桥接模式
[桥接模式例子](DesignPattern/BridgePattern)
### 观察者模式
[观察者模式例子](DesignPattern/ObserverPattern)
### 设计模式的六大原则
* 单一职责原则SRPSingle Responsibility Principle
@ -2209,41 +2500,6 @@ ssize_t write(int fd, const void *buf, size_t count);
* 迪米特法则LoDLaw of Demeter
* 开放封闭原则OCPOpen Close Principle
### 单例模式
```cpp
// 懒汉式单例模式
class Singleton
{
private:
Singleton() { }
static Singleton * pInstance;
public:
static Singleton * GetInstance()
{
if (pInstance == nullptr)
pInstance = new Singleton();
return pInstance;
}
};
// 线程安全的单例模式
class Singleton
{
private:
Singleton() { }
~Singleton() { }
Singleton(const Singleton &);
Singleton & operator = (const Singleton &);
public:
static Singleton & GetInstance()
{
static Singleton instance;
return instance;
}
};
```
## 链接装载库
### 内存、栈、堆
@ -2282,6 +2538,14 @@ public:
### 编译链接
#### 各平台文件格式
平台 | 可执行文件 | 目标文件 | 动态库/共享对象 | 静态库
---|---|---|---|---
Windows|exe|obj|dll|lib
Unix/Linux|ELF、out|o|so|a
Mac|Mach-O|o|dylib、tbd、framework|a、framework
#### 编译链接过程
1. 预编译(预编译器处理如 `#include`、`#define` 等预编译指令,生成 `.i``.ii` 文件)
@ -2365,41 +2629,379 @@ Linux 下的共享库就是普通的 ELF 共享对象。
* `LD_PRELOAD`:指定预先装载的一些共享库甚至是目标文件
* `LD_DEBUG`:打开动态链接器的调试功能
### Windows 的动态链接库Dynamic-Link Library
#### so 共享库的编写
<details><summary>Windows 动态链接库例子</summary>
<details><summary>使用 CLion 编写共享库</summary>
创建一个名为 MySharedLib 的共享库
CMakeLists.txt
```cmake
cmake_minimum_required(VERSION 3.10)
project(MySharedLib)
set(CMAKE_CXX_STANDARD 11)
add_library(MySharedLib SHARED library.cpp library.h)
```
library.h
DLL 头文件
```cpp
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MYSHAREDLIB_LIBRARY_H
#define MYSHAREDLIB_LIBRARY_H
#ifdef _WIN32
# ifdef MODULE_API_EXPORTS
# define MODULE_API __declspec(dllexport)
# else
# define MODULE_API __declspec(dllimport)
# endif
#else
# define MODULE_API
#endif
// 打印 Hello World!
void hello();
MODULE_API int module_init();
#ifdef __cplusplus
// 使用可变模版参数求和
template <typename T>
T sum(T t)
{
return t;
}
template <typename T, typename ...Types>
T sum(T first, Types ... rest)
{
return first + sum<T>(rest...);
}
#endif
```
DLL 源文件
```cpp
#define MODULE_API_EXPORTS
#include "module.h"
library.cpp
MODULE_API int module_init()
```cpp
#include <iostream>
#include "library.h"
void hello() {
std::cout << "Hello, World!" << std::endl;
}
```
</details>
#### so 共享库的使用(被可执行项目调用)
<details><summary>使用 CLion 调用共享库</summary>
创建一个名为 TestSharedLib 的可执行项目
CMakeLists.txt
```cmake
cmake_minimum_required(VERSION 3.10)
project(TestSharedLib)
# C++11 编译
set(CMAKE_CXX_STANDARD 11)
# 头文件路径
set(INC_DIR /home/xx/code/clion/MySharedLib)
# 库文件路径
set(LIB_DIR /home/xx/code/clion/MySharedLib/cmake-build-debug)
include_directories(${INC_DIR})
link_directories(${LIB_DIR})
link_libraries(MySharedLib)
add_executable(TestSharedLib main.cpp)
# 链接 MySharedLib 库
target_link_libraries(TestSharedLib MySharedLib)
```
main.cpp
```cpp
#include <iostream>
#include "library.h"
using std::cout;
using std::endl;
int main() {
hello();
cout << "1 + 2 = " << sum(1,2) << endl;
cout << "1 + 2 + 3 = " << sum(1,2,3) << endl;
return 0;
}
```
执行结果
```
Hello, World!
1 + 2 = 3
1 + 2 + 3 = 6
```
</details>
### Windows 应用程序入口函数
* GUIGraphical User Interface应用链接器选项`/SUBSYSTEM:WINDOWS`
* CUIConsole User Interface应用链接器选项`/SUBSYSTEM:CONSOLE`
<details><summary>_tWinMain 与 _tmain 函数声明</summary>
```cpp
Int WINAPI _tWinMain(
HINSTANCE hInstanceExe,
HINSTANCE,
PTSTR pszCmdLine,
int nCmdShow);
int _tmain(
int argc,
TCHAR *argv[],
TCHAR *envp[]);
```
</details>
应用程序类型|入口点函数|嵌入可执行文件的启动函数
---|---|---
处理ANSI字符的GUI应用程序|_tWinMain(WinMain)|WinMainCRTSartup
处理Unicode字符的GUI应用程序|_tWinMain(wWinMain)|wWinMainCRTSartup
处理ANSI字符的CUI应用程序|_tmain(Main)|mainCRTSartup
处理Unicode字符的CUI应用程序|_tmain(wMain)|wmainCRTSartup
动态链接库Dynamic-Link Library|DllMain|_DllMainCRTStartup
### Windows 的动态链接库Dynamic-Link Library
> 知识点来自《Windows核心编程第五版
#### 用处
* 扩展了应用程序的特性
* 简化了项目管理
* 有助于节省内存
* 促进了资源的共享
* 促进了本地化
* 有助于解决平台间的差异
* 可以用于特殊目的
#### 注意
* 创建 DLL事实上是在创建可供一个可执行模块调用的函数
* 当一个模块提供一个内存分配函数malloc、new的时候它必须同时提供另一个内存释放函数free、delete
* 在使用 C 和 C++ 混编的时候,要使用 extern "C" 修饰符
* 一个 DLL 可以导出函数、变量避免导出、C++ 类(导出导入需要同编译器,否则避免导出)
* DLL 模块cpp 文件中的 __declspec(dllexport) 写在 include 头文件之前
* 调用 DLL 的可执行模块cpp 文件的 __declspec(dllimport) 之前不应该定义 MYLIBAPI
#### 加载 Windows 程序的搜索顺序
1. 包含可执行文件的目录
2. Windows 的系统目录,可以通过 GetSystemDirectory 得到
3. 16 位的系统目录,即 Windows 目录中的 System 子目录
4. Windows 目录,可以通过 GetWindowsDirectory 得到
5. 进程的当前目录
6. PATH 环境变量中所列出的目录
#### DLL 入口函数
<details><summary>DllMain 函数</summary>
```cpp
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
/* do something useful */
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
// 第一次将一个DLL映射到进程地址空间时调用
// The DLL is being mapped into the process' address space.
break;
case DLL_THREAD_ATTACH:
// 当进程创建一个线程的时候用于告诉DLL执行与线程相关的初始化非主线程执行
// A thread is bing created.
break;
case DLL_THREAD_DETACH:
// 系统调用 ExitThread 线程退出前即将终止的线程通过告诉DLL执行与线程相关的清理
// A thread is exiting cleanly.
break;
case DLL_PROCESS_DETACH:
// 将一个DLL从进程的地址空间时调用
// The DLL is being unmapped from the process' address space.
break;
}
return (TRUE); // Used only for DLL_PROCESS_ATTACH
}
```
</details>
#### 载入卸载库
<details><summary>LoadLibrary、LoadLibraryExA、LoadPackagedLibrary、FreeLibrary、FreeLibraryAndExitThread 函数声明</summary>
```cpp
// 载入库
HMODULE WINAPI LoadLibrary(
_In_ LPCTSTR lpFileName
);
HMODULE LoadLibraryExA(
LPCSTR lpLibFileName,
HANDLE hFile,
DWORD dwFlags
);
// 若要在通用 Windows 平台UWP应用中加载 Win32 DLL需要调用 LoadPackagedLibrary而不是 LoadLibrary 或 LoadLibraryEx
HMODULE LoadPackagedLibrary(
LPCWSTR lpwLibFileName,
DWORD Reserved
);
// 卸载库
BOOL WINAPI FreeLibrary(
_In_ HMODULE hModule
);
// 卸载库和退出线程
VOID WINAPI FreeLibraryAndExitThread(
_In_ HMODULE hModule,
_In_ DWORD dwExitCode
);
```
</details>
#### 显示地链接到导出符号
<details><summary>GetProcAddress 函数声明</summary>
```cpp
FARPROC GetProcAddress(
HMODULE hInstDll,
PCSTR pszSymbolName // 只能接受 ANSI 字符串,不能是 Unicode
);
```
</details>
#### DumpBin.exe 查看 DLL 信息
`VS 的开发人员命令提示符` 使用 `DumpBin.exe` 可查看 DLL 库的导出段导出的变量、函数、类名的符号、相对虚拟地址RVArelative virtual address。如
```
DUMPBIN -exports D:\mydll.dll
```
#### LoadLibrary 与 FreeLibrary 流程图
<details><summary>LoadLibrary 与 FreeLibrary 流程图</summary>
##### LoadLibrary
![WindowsLoadLibrary](http://ojlsgreog.bkt.clouddn.com/WindowsLoadLibrary.png)
##### FreeLibrary
![WindowsFreeLibrary](http://ojlsgreog.bkt.clouddn.com/WindowsFreeLibrary.png)
</details>
#### DLL 库的编写(导出一个 DLL 模块)
<details><summary>DLL 库的编写(导出一个 DLL 模块)</summary>
DLL 头文件
```cpp
// MyLib.h
#ifdef MYLIBAPI
// MYLIBAPI 应该在全部 DLL 源文件的 include "Mylib.h" 之前被定义
// 全部函数/变量正在被导出
#else
// 这个头文件被一个exe源代码模块包含意味着全部函数/变量被导入
#define MYLIBAPI extern "C" __declspec(dllimport)
#endif
// 这里定义任何的数据结构和符号
// 定义导出的变量(避免导出变量)
MYLIBAPI int g_nResult;
// 定义导出函数原型
MYLIBAPI int Add(int nLeft, int nRight);
```
DLL 源文件
```cpp
// MyLibFile1.cpp
// 包含标准Windows和C运行时头文件
#include <windows.h>
// DLL源码文件导出的函数和变量
#define MYLIBAPI extern "C" __declspec(dllexport)
// 包含导出的数据结构、符号、函数、变量
#include "MyLib.h"
// 将此DLL源代码文件的代码放在此处
int g_nResult;
int Add(int nLeft, int nRight)
{
g_nResult = nLeft + nRight;
return g_nResult;
}
```
</details>
#### DLL 库的使用(运行时动态链接 DLL
<details><summary>DLL 库的使用(运行时动态链接 DLL</summary>
```cpp
// A simple program that uses LoadLibrary and
// GetProcAddress to access myPuts from Myputs.dll.
#include <windows.h>
#include <stdio.h>
typedef int (__cdecl *MYPROC)(LPWSTR);
int main( void )
{
HINSTANCE hinstLib;
MYPROC ProcAdd;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
// Get a handle to the DLL module.
hinstLib = LoadLibrary(TEXT("MyPuts.dll"));
// If the handle is valid, try to get the function address.
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "myPuts");
// If the function address is valid, call the function.
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
(ProcAdd) (L"Message sent to the DLL function\n");
}
// Free the DLL module.
fFreeResult = FreeLibrary(hinstLib);
}
// If unable to call the DLL function, use an alternative.
if (! fRunTimeLinkSuccess)
printf("Message printed from executable\n");
return 0;
}
```
@ -2521,7 +3123,7 @@ MODULE_API int module_init()
## 招聘时间岗位
* [牛客网 . 2018 IT名企校招指南](https://www.nowcoder.com/activity/campus2018)
* [牛客网 . 2019 IT名企校招指南](https://www.nowcoder.com/activity/campus2019)
## 面试题目经验

View File

@ -54,7 +54,7 @@ empty|返回 vector 是否为空
reserve|请求 vector 容量至少足以包含 n参数个元素
shrink_to_fit|要求容器减小其 capacity容量以适应其 size元素数量
operator[]|返回容器中第 n参数个位置的元素的引用
at|返回中第 n参数个位置的元素的引用
at|返回容器中第 n参数个位置的元素的引用
front|返回对容器中第一个元素的引用
back|返回对容器中最后一个元素的引用
data|返回指向容器中第一个元素的指针
@ -183,10 +183,10 @@ equal(beg1, end1, beg2); // 比较每个元素,确定两个序列是否相等
equal(beg1, end1, beg2, binaryPred); // 比较每个元素,确定两个序列是否相等。
// 二分搜索算法传入前向迭代器或随机访问迭代器random-access iterator要求序列中的元素已经是有序的。通过小于运算符<)或 comp 比较操作实现比较。
lower_bound(beg, end, val); // 返回一个迭代器,表示第一个小于等于 val 的元素,不存在则返回 end
lower_bound(beg, end, val, comp); // 返回一个迭代器,表示第一个小于等于 val 的元素,不存在则返回 end
upper_bound(beg, end, val); // 返回一个迭代器,表示第一个大于 val 的元素,不存在则返回 end
upper_bound(beg, end, val, comp); // 返回一个迭代器,表示第一个大于 val 的元素,不存在则返回 end
lower_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end
lower_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中的第一个大于等于值 val 的位置的迭代器,不存在则返回 end
upper_bound(beg, end, val); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end
upper_bound(beg, end, val, comp); // 返回一个非递减序列 [beg, end) 中第一个大于 val 的位置的迭代器,不存在则返回 end
equal_range(beg, end, val); // 返回一个 pair其 first 成员是 lower_bound 返回的迭代器,其 second 成员是 upper_bound 返回的迭代器
binary_search(beg, end, val); // 返回一个 bool 值,指出序列中是否包含等于 val 的元素。对于两个值 x 和 y当 x 不小于 y 且 y 也不小于 x 时,认为它们相等。
@ -206,7 +206,7 @@ transform(beg, end, beg2, dest, binaryOp); // 调用给定操作(二元操作
replace_copy(beg, end, dest, old_val, new_val); // 将每个元素拷贝到 dest将等于 old_val 的的元素替换为 new_val
replace_copy_if(beg, end, dest, unaryPred, new_val); // 将每个元素拷贝到 dest将满足 unaryPred 的的元素替换为 new_val
merge(beg1, end1, beg2, end2, dest); // 两个输入序列必须都是有序的,用 < 运算符将合并后的序列写入到 dest
merge(beg1, end1, beg2, end2, dest, comp) // 两个输入序列必须都是有序的使用给定的比较操作comp将合并后的序列写入到 dest 中
merge(beg1, end1, beg2, end2, dest, comp); // 两个输入序列必须都是有序的使用给定的比较操作comp将合并后的序列写入到 dest 中
// 使用前向迭代器的写算法,要求前向迭代器
iter_swap(iter1, iter2); // 交换 iter1 和 iter2 所表示的元素,返回 void
@ -218,7 +218,7 @@ replace_if(beg, end, unaryPred, new_val); // 用 new_val 替换满足 unaryPred
copy_backward(beg, end, dest); // 从输入范围中拷贝元素到指定目的位置。如果范围为空,则返回值为 dest否则返回值表示从 *beg 中拷贝或移动的元素。
move_backward(beg, end, dest); // 从输入范围中移动元素到指定目的位置。如果范围为空,则返回值为 dest否则,返回值表示从 *beg 中拷贝或移动的元素。
inplace_merge(beg, mid, end); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用 < 比较元素
inplace_merge(beg, mid, end, comp) // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。
inplace_merge(beg, mid, end, comp); // 将同一个序列中的两个有序子序列合并为单一的有序序列。beg 到 mid 间的子序列和 mid 到 end 间的子序列被合并,并被写入到原序列中。使用给定的 comp 操作。
// 划分算法要求双向选代器bidirectional iterator
is_partitioned(beg, end, unaryPred); // 如果所有满足谓词 unaryPred 的元素都在不满足 unarypred 的元素之前,则返回 true。若序列为空也返回 true
@ -230,8 +230,8 @@ partition(beg, end, unaryPred); // 使用 unaryPred 划分输入序列。满足
// 排序算法要求随机访问迭代器random-access iterator
sort(beg, end); // 排序整个范围
stable_sort(beg, end); // 排序整个范围(稳定排序)
sort(beg, end, comp) // 排序整个范围
stable_sort(beg, end, comp) // 排序整个范围(稳定排序)
sort(beg, end, comp); // 排序整个范围
stable_sort(beg, end, comp); // 排序整个范围(稳定排序)
is_sorted(beg, end); // 返回一个 bool 值,指出整个输入序列是否有序
is_sorted(beg, end, comp); // 返回一个 bool 值,指出整个输入序列是否有序
is_sorted_until(beg, end); // 在输入序列中査找最长初始有序子序列,并返回子序列的尾后迭代器

View File

@ -35,7 +35,7 @@ array是固定大小的顺序容器它们保存了一个以严格的线性顺
数组容器的另一个独特特性是它们可以被当作元组对象来处理array头部重载get函数来访问数组元素就像它是一个元组以及专门的tuple_size和tuple_element类型。
```
```cpp
template < class T, size_t N > class array;
```
@ -47,14 +47,14 @@ template < class T, size_t N > class array;
![](https://i.stack.imgur.com/oa3EQ.png)
```
```cpp
iterator begin() noexcept;
const_iterator begin() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -78,14 +78,14 @@ myarray contains: 2 16 77 34 50
返回指向数组容器中最后一个元素之后的理论元素的迭代器。
```
```cpp
iterator end() noexcept;
const_iterator end() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -111,12 +111,12 @@ myarray contains: 5 19 77 34 99
返回指向数组容器中最后一个元素的反向迭代器。
```
```cpp
reverse_iterator rbeginnoexcept;
const_reverse_iterator rbeginconst noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -140,13 +140,13 @@ myarray contains: 14 80 26 4
返回一个反向迭代器,指向数组中第一个元素之前的理论元素(这被认为是它的反向结束)。
```
```cpp
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -170,11 +170,11 @@ myarray contains: 14 80 26 4
#### array::cbegin
返回指向数组容器中第一个元素的常量迭代器const_iterator这个迭代器可以增加和减少但是不能用来修改它指向的内容。
```
```cpp
const_iterator cbeginconst noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -199,11 +199,11 @@ myarray contains: 2 16 77 34 50
#### array::cend
返回指向数组容器中最后一个元素之后的理论元素的常量迭代器const_iterator。这个迭代器可以增加和减少但是不能用来修改它指向的内容。
```
```cpp
const_iterator cend() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -227,11 +227,11 @@ myarray contains: 2 16 77 34 50
#### array::crbegin
返回指向数组容器中最后一个元素的常量反向迭代器const_reverse_iterator
```
```cpp
const_reverse_iterator crbeginconst noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -256,11 +256,11 @@ myarray backwards: 60 50 40 30 20 10
返回指向数组中第一个元素之前的理论元素的常量反向迭代器const_reverse_iterator它被认为是其反向结束。
```
```cpp
const_reverse_iterator crend() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -286,11 +286,11 @@ myarray backwards: 60 50 40 30 20 10
返回数组容器中元素的数量。
```
```cpp
constexpr size_type sizenoexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -310,11 +310,11 @@ sizeof(myints): 20
```
#### array::max_size
返回数组容器可容纳的最大元素数。数组对象的max_size与其size一样始终等于用于实例化数组模板类的第二个模板参数。
```
```cpp
constexpr size_type max_size() noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -335,11 +335,11 @@ max_size of myints: 10
#### array::empty
返回一个布尔值指示数组容器是否为空即它的size()是否为0。
```
```cpp
constexpr bool empty() noexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -359,12 +359,12 @@ second is not empt
```
#### array::operator[]
返回数组中第n个位置的元素的引用。与array::at相似但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围而array::operator[]不检查边界。
```
```cpp
reference operator[] (size_type n);
const_reference operator[] (size_type n) const;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -392,12 +392,12 @@ myarray contains: 0 1 2 3 4 5 6 7 8 9
```
#### array::at
返回数组中第n个位置的元素的引用。与array::operator[]相似但array::at会检查数组边界并通过抛出一个out_of_range异常来判断n是否超出范围而array::operator[]不检查边界。
```
```cpp
reference at ( size_type n );
const_reference at ( size_type n ) const;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -426,12 +426,12 @@ myarray contains: 0 1 2 3 4 5 6 7 8 9
#### array::front
返回对数组容器中第一个元素的引用。array::begin返回的是迭代器array::front返回的是直接引用。
在空容器上调用此函数会导致未定义的行为。
```
```cpp
reference front();
const_reference front() const;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -461,12 +461,12 @@ myarray now contains: 100 16 77
#### array::back
返回对数组容器中最后一个元素的引用。array::end返回的是迭代器array::back返回的是直接引用。
在空容器上调用此函数会导致未定义的行为。
```
```cpp
reference back();
const_reference back() const;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -496,12 +496,12 @@ myarray now contains: 5 19 50
返回指向数组对象中第一个元素的指针。
由于数组中的元素存储在连续的存储位置,所以检索到的指针可以偏移以访问数组中的任何元素。
```
```cpp
value_type* data() noexcept;
const value_type* data() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <cstring>
#include <array>
@ -524,11 +524,11 @@ Test string
```
#### array::fill
用val填充数组所有元素将val设置为数组对象中所有元素的值。
```
```cpp
void fill (const value_type& val);
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -553,11 +553,11 @@ myarray contains: 5 5 5 5 5 5
通过x的内容交换数组的内容这是另一个相同类型的数组对象包括相同的大小
与其他容器的交换成员函数不同,此成员函数通过在各个元素之间执行与其大小相同的单独交换操作,以线性时间运行。
```
```cpp
void swap (array& x) noexcept(noexcept(swap(declval<value_type&>(),declval<value_type&>())));
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -586,13 +586,13 @@ second: 10 20 30 40 50
```
#### getarray
形如std::get<0>(myarray);传入一个数组容器,返回指定位置元素的引用。
```
```cpp
template <size_t Iclass Tsize_t N> Tgetarray <TN>arrnoexcept;
template <size_t Iclass Tsize_t N> T && getarray <TN> && arrnoexcept;
template <size_t Iclass Tsize_t N> const Tgetconst array <TN>arrnoexcept;
```
Example
```
```cpp
#include <iostream>
#include <array>
#include <tuple>
@ -621,7 +621,7 @@ first element in mytuple: 10
```
#### relational operators (array)
形如arrayA != arrayB、arrayA > arrayB依此比较数组每个元素的大小关系。
```
```cpp
1
template <class Tsize_T N>
bool operator ==const array <TN>lhsconst array <TN>rhs;
@ -642,7 +642,7 @@ template <class Tsize_T N>
bool operator> =const array <TN>lhsconst array <TN>rhs;
```
Example
```
```cpp
#include <iostream>
#include <array>
@ -680,7 +680,7 @@ vector是表示可以改变大小的数组的序列容器。
相反vector容器可以分配一些额外的存储以适应可能的增长并且因此容器可以具有比严格需要包含其元素其大小的存储更大的实际容量。库可以实现不同的策略的增长到内存使用和重新分配之间的平衡但在任何情况下再分配应仅在对数生长的间隔发生尺寸使得在所述载体的末端各个元件的插入可以与提供分期常量时间复杂性。
因此,与阵列相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。
因此,与数组相比,载体消耗更多的内存来交换管理存储和以有效方式动态增长的能力。
与其他动态序列容器dequeslists和 forward\_lists 相比vector非常有效地访问其元素就像数组一样并相对有效地从元素末尾添加或移除元素。对于涉及插入或移除除了结尾之外的位置的元素的操作它们执行比其他位置更差的操作并且具有比列表和 forward\_lists 更不一致的迭代器和引用。
@ -689,7 +689,7 @@ vector是表示可以改变大小的数组的序列容器。
* 在尾部增删元素 - 平摊amortized常数 O(1)}}
* 增删元素 - 至 vector 尾部的线性距离 O(n)}}
```
```cpp
template < class T, class Alloc = allocator<T> > class vector;
```
![](http://img.blog.csdn.net/20160406151211233)
@ -710,7 +710,7 @@ x保持未指定但有效的状态。
6初始化列表构造函数
构造一个容器中的每个元件中的一个拷贝的IL以相同的顺序。
```
```cpp
default (1)
explicit vector (const allocator_type& alloc = allocator_type());
fill (2)
@ -732,7 +732,7 @@ vector (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -762,12 +762,12 @@ The contents of fifth are: 16 2 77 29
```
#### vector::~vector
销毁容器对象。这将在每个包含的元素上调用allocator_traits::destroy并使用其分配器释放由矢量分配的所有存储容量。
```
```cpp
~vector();
```
#### vector::operator=
将新内容分配给容器,替换其当前内容,并相应地修改其大小。
```
```cpp
copy (1)
vector& operator= (const vector& x);
move (2)
@ -812,11 +812,11 @@ Size of bar: 3
这是vector中保存的实际对象的数量不一定等于其存储容量。
```
```cpp
size_type size() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -848,11 +848,11 @@ Output
返回该vector可容纳的元素的最大数量。由于已知的系统或库实现限制
这是容器可以达到的最大潜在大小,但容器无法保证能够达到该大小:在达到该大小之前的任何时间,仍然无法分配存储。
```
```cpp
size_type max_size() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -885,12 +885,12 @@ max_size: 1073741823
如果n也大于当前的容器的capacity容量分配的存储空间将自动重新分配。
注意这个函数通过插入或者删除元素的内容来改变容器的实际内容。
```
```cpp
void resize (size_type n);
void resize (size_type n, const value_type& val);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -919,11 +919,11 @@ myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0
```
#### vector::capacity
返回当前为vector分配的存储空间的大小用元素表示。这个capacity(容量)不一定等于vector的size。它可以相等或更大额外的空间允许适应增长而不需要重新分配每个插入。
```
```cpp
size_type capacity() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -948,11 +948,11 @@ max_size: 1073741823
```
#### vector::empty
返回vector是否为空它的size是否为0
```
```cpp
bool empty() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -986,11 +986,11 @@ total: 55
在所有其他情况下函数调用不会导致重新分配并且vector容量不受影响。
这个函数对vector大小没有影响也不能改变它的元素。
```
```cpp
void reserve (size_type n);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1041,11 +1041,11 @@ capacity changed: 100
要求容器减小其capacity(容量)以适应其尺寸。
该请求是非绑定的并且容器实现可以自由地进行优化并且保持capacity大于其size的vector。 这可能导致重新分配,但对矢量大小没有影响,并且不能改变其元素。
```
```cpp
void shrink_to_fit();
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1085,7 +1085,7 @@ Possible output
在初始化列表版本3新内容是以相同顺序作为初始化列表传递的值的副本。
所述内部分配器被用于(通过其性状),以分配和解除分配存储器如果重新分配发生。它也习惯于摧毁所有现有的元素,并构建新的元素。
```
```cpp
range (1)
template <class InputIterator>
void assign (InputIterator first, InputIterator last);
@ -1095,7 +1095,7 @@ initializer list (3)
void assign (initializer_list<value_type> il);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1185,12 +1185,12 @@ vector<_Tp,_Alloc>::operator=(const vector<_Tp, _Alloc>& __x)
在vector的最后一个元素之后添加一个新元素。val的内容被复制或移动到新的元素。
这有效地将容器size增加了一个如果新的矢量size超过了当前vector的capacity则导致所分配的存储空间自动重新分配。
```
```cpp
void push_back (const value_type& val);
void push_back (value_type&& val);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1215,11 +1215,11 @@ int main ()
删除vector中的最后一个元素有效地将容器size减少一个。
这破坏了被删除的元素。
```
```cpp
void pop_back();
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1250,7 +1250,7 @@ The elements of myvector add up to 600
通过在指定位置的元素之前插入新元素来扩展该vector通过插入元素的数量有效地增加容器大小。 这会导致分配的存储空间自动重新分配只有在新的vector的size超过当前的vector的capacity的情况下。
由于vector使用数组作为其基础存储因此除了将元素插入到vector末尾之后或vector的begin之前其他位置会导致容器重新定位位置之后的所有元素到他们的新位置。与其他种类的序列容器例如list或forward_list执行相同操作的操作相比这通常是低效的操作。
```
```cpp
single element (1)
iterator insert (const_iterator position, const value_type& val);
fill (2)
@ -1264,7 +1264,7 @@ initializer list (5)
iterator insert (const_iterator position, initializer_list<value_type> il);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1326,12 +1326,12 @@ int main()
这有效地减少了被去除的元素的数量,从而破坏了容器的大小。
由于vector使用一个数组作为其底层存储所以删除除vector结束位置之后或vector的begin之前的元素外将导致容器将段被擦除后的所有元素重新定位到新的位置。与其他种类的序列容器例如list或forward_list执行相同操作的操作相比这通常是低效的操作。
```
```cpp
iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1366,11 +1366,11 @@ myvector contains: 4 5 7 8 9 10
在调用这个成员函数之后这个容器中的元素是那些在调用之前在x中的元素而x的元素是在这个元素中的元素。所有迭代器引用和指针对交换对象保持有效。
请注意,非成员函数存在具有相同名称的交换,并使用与此成员函数相似的优化来重载该算法。
```
```cpp
void swap (vector& x);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1403,11 +1403,11 @@ bar contains: 100 100 100
从vector中删除所有的元素被销毁留下size为0的容器。
不保证重新分配,并且由于调用此函数, vector的capacity不保证发生变化。强制重新分配的典型替代方法是使用swap`vector<T>().swap(x); // clear x reallocating `
```
```cpp
void clear() noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1467,12 +1467,12 @@ v1 capacity = 5
该元素是通过调用allocator_traits::construct来转换args来创建的。插入一个类似的成员函数将现有对象复制或移动到容器中。
```
```cpp
template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1504,7 +1504,7 @@ myvector contains: 10 200 100 20 30 300
该元素是通过调用allocator_traits :: construct来转换args来创建的。
与push\_back相比emplace\_back可以避免额外的复制和移动操作。
```
```cpp
template <class... Args>
void emplace_back (Args&&... args);
```
@ -1573,11 +1573,11 @@ Franklin Delano Roosevelt was re-elected president of the USA in 1936.
```
#### vector::get_allocator
返回与vector关联的构造器对象的副本。
```
```cpp
allocator_type get_allocator() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <vector>
@ -1628,7 +1628,7 @@ deque上常见操作的复杂性效率如下
* 随机访问 - 常数O(1)
* 在结尾或开头插入或移除元素 - 摊销不变O(1)
* 插入或移除元素 - 线性O(n)
```
```cpp
template < class T, class Alloc = allocator<T> > class deque;
```
![](http://img.blog.csdn.net/20170727225856144?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRlg2Nzc1ODg=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
@ -1639,7 +1639,7 @@ template < class T, class Alloc = allocator<T> > class deque;
构造一个deque容器对象根据所使用的构造函数版本初始化它的内容
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1674,12 +1674,12 @@ The contents of fifth are: 16 2 77 29
在当前的最后一个元素之后 在deque容器的末尾添加一个新元素。val的内容被复制或移动到新的元素。
这有效地增加了一个容器的大小。
```
```cpp
void push_back (const value_type& val);
void push_back (value_type&& val);
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1704,12 +1704,12 @@ int main ()
在deque容器的开始位置插入一个新的元素位于当前的第一个元素之前。val的内容被复制或移动到插入的元素。
这有效地增加了一个容器的大小。
```
```cpp
void push_front (const value_type& val);
void push_front (value_type&& val);
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1736,11 +1736,11 @@ Output
这破坏了被删除的元素。
```
```cpp
void pop_back();
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1771,11 +1771,11 @@ The elements of mydeque add up to 60
删除deque容器中的第一个元素有效地减小其大小。
这破坏了被删除的元素。
```
```cpp
void pop_front();
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1812,12 +1812,12 @@ The final size of mydeque is 0
该元素是通过调用allocator_traits::construct来转换args来创建的。
存在一个类似的成员函数push_front它可以将现有对象复制或移动到容器中。
```
```cpp
template <class... Args>
void emplace_front (Args&&... args);
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1848,12 +1848,12 @@ mydeque contains: 222 111 10 20 30
该元素是通过调用allocator_traits::construct来转换args来创建的。
存在一个类似的成员函数push_back它可以将现有对象复制或移动到容器中
```
```cpp
template <class... Args>
void emplace_back (Args&&... args);
```
Example
```
```cpp
#include <iostream>
#include <deque>
@ -1894,7 +1894,7 @@ forward\_list单向链表被实现为单链表; 单链表可以将它们
#### forward\_list::forward\_list
```
```cpp
default (1)
explicit forward_list (const allocator_type& alloc = allocator_type());
fill (2)
@ -1916,7 +1916,7 @@ forward_list (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());
```
Example
```
```cpp
#include <iostream>
#include <forward_list>
@ -1959,12 +1959,12 @@ sixth: 3 52 25 90
返回的迭代器不应被解除引用它是为了用作成员函数的参数emplace\_afterinsert\_aftererase\_after或splice\_after指定序列其中执行该动作的位置的开始位置。
```
```cpp
iterator before_begin() noexcept;
const_iterator before_begin() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <forward_list>
@ -1991,11 +1991,11 @@ mylist contains: 11 20 30 40 50
一个常量性是指向常量内容的迭代器。这个迭代器可以增加和减少除非它本身也是const就像forward\_list::before\_begin返回的迭代器一样但不能用来修改它指向的内容。
返回的价值不得解除引用。
```
```cpp
const_iterator cbefore_begin() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <forward_list>
@ -2035,11 +2035,13 @@ map 是关联容器,按照特定顺序存储由 key value (键值) 和 mapped
在映射中键值通常用于对元素进行排序和唯一标识而映射的值存储与此键关联的内容。该类型的键和映射的值可能不同并且在部件类型被分组在一起VALUE_TYPE这是一种对类型结合两种
`typedef pair<const Key, T> value_type;`
```cpp
typedef pair<const Key, T> value_type;
```
在内部映射中的元素总是按照由其内部比较对象比较类型指示的特定的严格弱排序标准按键排序。映射容器通常比unordered_map容器慢以通过它们的键来访问各个元素但是它们允许基于它们的顺序对子集进行直接迭代。 在该映射值地图可以直接通过使用其相应的键来访问括号运算符((操作符[] )。 映射通常如实施
```
```cpp
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
@ -2072,7 +2074,7 @@ x保持未指定但有效的状态。
用il中的每个元素的副本构造一个容器。
```
```cpp
empty (1)
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
@ -2094,7 +2096,7 @@ map (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2132,12 +2134,12 @@ int main ()
由于map容器始终保持其元素的顺序所以开始指向遵循容器排序标准的元素。
如果容器是空的,则返回的迭代器值不应被解除引用。
```
```cpp
iterator begin() noexcept;
const_iterator begin() const noexcept;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2166,11 +2168,11 @@ c => 300
#### map::key_comp
返回容器用于比较键的比较对象的副本。
```
```cpp
key_compare key_comp() const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2208,11 +2210,11 @@ c => 300
#### map::value_comp
返回可用于比较两个元素的比较对象,以获取第一个元素的键是否在第二个元素之前。
```
```cpp
value_compare value_comp() const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2249,12 +2251,12 @@ z => 3003
如果容器的比较对象自反地返回假不管元素作为参数传递的顺序则两个key被认为是等同的。
另一个成员函数map::count可以用来检查一个特定的键是否存在。
```
```cpp
iterator find (const key_type& k);
const_iterator find (const key_type& k) const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2294,11 +2296,11 @@ d => 200
由于地图容器中的所有元素都是唯一的因此该函数只能返回1如果找到该元素或返回零否则
如果容器的比较对象自反地返回错误(即,不管按键作为参数传递的顺序),则两个键被认为是等同的。
```
```cpp
size_type count (const key_type& k) const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2344,12 +2346,12 @@ g is not an element of mymap.
如果map类用默认的比较类型less实例化则函数返回一个迭代器到第一个元素其键不小于k。
一个类似的成员函数upper\_bound具有相同的行为lower\_bound除非映射包含一个key值等于k的元素在这种情况下lower\_bound返回指向该元素的迭代器而upper\_bound返回指向下一个元素的迭代器。
```
```cpp
iterator lower_bound (const key_type& k);
const_iterator lower_bound (const key_type& k) const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2393,12 +2395,12 @@ e => 100
类似的成员函数lower\_bound具有与upper\_bound相同的行为除了map包含一个元素其键值等于k在这种情况下lower\_bound返回指向该元素的迭代器而upper\_bound返回指向下一个元素的迭代器。
```
```cpp
iterator upper_bound (const key_type& k);
const_iterator upper_bound (const key_type& k) const;
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2440,12 +2442,12 @@ e => 100
如果没有找到匹配则返回的范围具有零的长度与两个迭代器指向具有考虑去后一个密钥对所述第一元件ķ根据容器的内部比较对象key\_comp。如果容器的比较对象返回false则两个键被认为是等价的。
```
```cpp
pair<const_iterator,const_iterator> equal_range (const key_type& k) const;
pair<iterator,iterator> equal_range (const key_type& k);
```
Example
```
```cpp
#include <iostream>
#include <map>
@ -2510,12 +2512,12 @@ unordered\_map、unodered\_multimap结构
元组是一个能够容纳元素集合的对象。每个元素可以是不同的类型。
```
```cpp
template <class... Types> class tuple;
```
Example
```
```cpp
#include <iostream> // std::cout
#include <tuple> // std::tuple, std::get, std::tie, std::ignore
@ -2578,7 +2580,7 @@ foo contains: 100 y
和上面的版本一样除了每个元素都是使用allocator alloc构造的。
```
```cpp
default (1)
constexpr tuple();
copy / move (2)
@ -2619,7 +2621,7 @@ template<class Alloc, class U1, class U2>
tuple (allocator_arg_t aa, const Alloc& alloc, pair<U1,U2>&& pr);
```
Example
```
```cpp
#include <iostream> // std::cout
#include <utility> // std::make_pair
#include <tuple> // std::tuple, std::make_tuple, std::get
@ -2656,7 +2658,7 @@ pair的实现是一个结构体主要的两个成员变量是first second 因
* 可以将两个类型数据组合成一个如map<key, value>
* 当某个函数需要两个返回值时
```
```cpp
template <class T1, class T2> struct pair;
```
#### pair::pair
@ -2681,7 +2683,7 @@ template <class T1, class T2> struct pair;
构造成员 first 和 second 到位传递元素first\_args 作为参数的构造函数 first和元素 second\_args 到的构造函数 second 。
```
```cpp
default (1)
constexpr pair();
copy / move (2)
@ -2700,7 +2702,7 @@ template <class... Args1, class... Args2>
Example
```
```cpp
#include <utility> // std::pair, std::make_pair
#include <string> // std::string
#include <iostream> // std::cout
@ -2726,4 +2728,4 @@ Output
The price of lightbulbs is $0.99
The price of shoes is $39.9
The price of tomatoes is $2.3
```
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB