1.auto和decltype关键字
// 用auto告知编译器模板的返回类型需要自动推导
// 用decltype(expression)告知编译器返回类型根据expression推导
// -> decltype(expression) 这种表示法叫做尾置返回类型
template <typename T, typename U>
auto f(T t, U u) -> decltype(t + u)
{
return t + u;
}
// C++14
template <typename T, typename U>
decltype(auto) sum(T x, U y) // 根据return后面的表达式自动推断返回类型
{ // 注意这里是以decltype的类型推导规则来推断返回类型
return x + y;
}
2.完美转发
std::forward(x) //原来是啥类型的,经过forward之后就变成啥类型的
当模板参数为引用类型T、T&&时,返回右值引用;
当模板参数为引用类型T&时,返回左值引用。
将一个传进函数的参数原封不动的传递出去,(右值引用类型是独立于值的,一个右值引用参数作为函数的形参,
在函数内部再转发成改参数的时候就变成一个左值,并不是它原来的类型)
3.function
定义为:
std::function<int(int,int)> mod = [](int i, int j){return i % j; };
这里std::function<int(int,int)>的作用就类似于int和auto。
4.cbegin()和cend()决定返回的迭代器类型为const,防止对原有数据进行更改
5.数组指针定义:含有10个整数元素的数组
typedef int arrT[10]
using arrT=int[10]
6.尾置返回类型,针对任何函数
auto func(int i)->int(*)[10];//返回的是一个指针,该指针指向了含有10个整数的数组
7.constexpr构造函数
- emplace会再容器管理的内存中直接创建对象,而push_back会创建一个临时对象,再压入容器中
9.shrink_to_fit();//使得容器的Capacity与Size匹配.
10.固定搭配写法:
pid_t gettid()
{
return (pid_t)syscall(SYS_gettid);//返回线程id唯一标识
//或者写成 static_cast<pid_t>(syscall(SYS_gettid));
}
- epoll使用方法:
(1) int efpd=epoll_create(int size);
(2) nRet=epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&ev); //
- 内存池
开发原因:
高并发时较小内存块使用时,系统调用频繁(malloc,free)降低系统执行效率;
频繁使用时增加系统内存碎片,降低内存使用效率;
无垃圾回收,容易造成内粗泄露,导致内存枯竭;
13.上行转换:把派生类的指针和引用转换成基类表示;
下行转换:把基类的指针和引用转换成派生类;
- promise通常与future配合使用,在一个线程中传入数据,在另一个线程中获取
1)std::future类模板,future对象提供访问异步操作结果的机制,很轻松解决从异步任务中返回结果。(方便获取结果)
a.std::async 函数会返回一个std::future
b.std::promise::get_future 调用成员函数,获取 std::future
c.std::packaged_task::get_future 调用成员函数,获取 std::future
std::future result = std::async({
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return 8;
});//创建异步线程
std::cout << "the future result : " << result.get() << std::endl;//获取线程执行结果
std::cout << "the future status : " << result.valid() << std::endl;
#include <iostream>
#include <future>
#include <chrono>
void Thread_Fun1(std::promise<int> &p)
{
//为了突出效果,可以使线程休眠5s
std::this_thread::sleep_for(std::chrono::seconds(5));
int iVal = 233;
std::cout << "传入数据(int):" << iVal << std::endl;
//传入数据iVal
p.set_value(iVal);//可以传入函数: p.set_value(std::bind(&函数,std::placeholders::_1));
}
void Thread_Fun2(std::future<int> &f)
{
//阻塞函数,直到收到相关联的std::promise对象传入的数据
auto iVal = f.get(); //iVal = 233 //或者获取函数,再执行iVal(100);
std::cout << "收到数据(int):" << iVal << std::endl;
}
int main()
{
//声明一个std::promise对象pr1,其保存的值类型为int
std::promise<int> pr1;
//声明一个std::future对象fu1,并通过std::promise的get_future()函数与pr1绑定
std::future<int> fu1 = pr1.get_future();
//创建一个线程t1,将函数Thread_Fun1及对象pr1放在线程里面执行
std::thread t1(Thread_Fun1, std::ref(pr1));
//创建一个线程t2,将函数Thread_Fun2及对象fu1放在线程里面执行
std::thread t2(Thread_Fun2, std::ref(fu1));
//阻塞至线程结束
t1.join();
t2.join();
return 1;
}
- CMakeLists.txt写法总结
rm -rf * #表示删除当前目录
1)编译main.cpp
PROJECT(HELLO) # 指定工程名字
SET(SRC_LIST main.cpp) #显示指定变量 多个cpp文件的则:SET(SRC_LIST p1.cpp p2.cpp)
MESSAGE(STATUS “This is BINARY dir” ${HELLO_BINARY_DIR}) #向终端输出用户自定义的信息
MESSAGE(STATUS “This is SOURCE dir” ${HELLO_SOURCE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST}) #生成可执行文件hello 源文件读取变量SRC_LIST内容 或者直接ADD_EXECUTABLE(hello ${hello main.cpp})
cmake . #表示在当前目录编译
./hello
- 变量使用${}取值,指令一般用大写字母
3) 上面的例子是内部构建,会产生许多临时文件,外部构建会把生成的临时文件放到build目录下,在build目录下运行make来构建工程
mkdir build
cd build/
cmake … #…表示上一级目录
- 存在目录
(使用tree能够看到目录结构)
.
|–build
|–CMakeLists.txt
|–src
|–CMakeLists.txt
|–main.cpp
-
Linux中C++基础
1) .o 目标文件,相当于win的.obj
.so 相当于win的dll
.a 静态库
*.inl 文件是内联函数的源文件,通常内联函数在C++头文件中实现,但有时为了考虑将其实现与头文件分离,
故意在另一文件中实现,通常它在声明内联函数的头文件的末尾被#include语句包含进来。 -
oprerator++(int){}//对i++重载
operator++(){}//对++i重载
18.基础C库函数实现
//my_memcpy实现重叠内存转移
char* my_memcpy(char* _Dest, const char* _Source, int count)
{
//检查传入参数的有效性
assert(NULL != _Dest);
assert(NULL != _Source);
if (NULL ==_Dest || NULL == _Source)
return NULL;
char* ret = _Dest;
/**
_Dest和_Source的内存地址有三种排列组合:
1. _Dest和_Source没有发生重叠;
2. _Dest和_Source地址重叠,且_Dest的地址大于_Source的地址;
3. _Dest和_Source地址重叠,_Dest的地址小于_Source的地址;
第一种情况和第三种情况,直接从低位字节开始复制,即可;
第二种情况,必须从高位字节开始复制,才能保证复制正确。
*/
if (_Dest > _Source && _Dest < _Source + count )
{
_Dest = _Dest + count - 1;
_Source = _Source + count - 1;
while(count--)
{
*_Dest-- = *_Source--;
}
}else
{
while(count--)
{
*_Dest++ = *_Source++;
}
}
return ret;
}