本文主要探讨c++相关知识。
对象优化
Test t;t = Test(1);调用构造函数构造临时对象再通过赋值运算符重载,语句结束临时对象析构
Test t = Test t(1);<==>Test t(1);编译器优化临时对象,直接构造新对象
Test t = (Test)1;显示类型强转,调用Test(int num):num(num){}构造函数
Test t = 30;隐式类型强转,调用Test(int num):num(num){}构造函数
Test *t = &Test(1);指针指向临时对象,语句结束对象析构,指针指向的数据无法使用,编译不过
const Test *t = &Test(1);临时量的值当做常量传出,语句结束后指针指向的数据仍可使用
对象优化:函数传参传引用,值传递会构建和析构形参对象;函数返回临时对象,避免在调用函数中和接受返回的过程中会构建和析构对象
左右值
左值引用为有内存和名字,右值引用为无名字或内存(临时变量)
左值引用:int a = 1;int &b = a;
右值引用:int &a = 1;int &&d = 20;右值绑定到右值引用int &&c = a;左值不能绑定到右值引用int &&f = d;右值引用本身是左值
编译器优先匹配参数带右值引用的赋值重载函数可省去内存开辟,相当于浅拷贝
std::move()返回右值引用可减少内存开辟
模板中&&的引用可接受左值右值引用(包含const)
完美转发std::forward可保证模板中&&的右值引用不会被改变为左值
智能指针
智能指针是类模板,对象出作用域自动析构
智能指针是裸指针封装,构造函数初始化,析构函数释放资源
定义在堆上的智能能指针和普通指针相同都要手动释放资源
auto_ptr不带引用计数且为浅拷贝,拷贝后前一资源置空
unique_ptr独占资源且不带引用计数
两指针指向同一资源,编译报错即拷贝构造和赋值构造为为private或delete
unique_ptr可移动构造把资源转交给另一指针,前一指针失效
shared_ptr多指针指向同一资源且带有引用计数
引用计数为0时,share_ptr资源释放
定义对象用强指针shared_ptr,引用对象用弱指针weak_ptr解决交叉引用资源泄露
weak_ptr不改变引用计数,不持有引用计数,持有观察者计数,只判定资源存在性
weak_ptr持有的引用计数,不是资源的引用计数,而是同一个资源的观察者的计数
weak_ptr通过lock方法提升为shared_ptr强指针才可访问资源
多线程访问共享资源时share_ptr定义资源,线程中传入weak_ptr提权访问资源,提权失败则资源被占用或释放,保证资源访问安全
std::function<返回值类型(传入参数类型)> 方法名
lambda + function可用于实现删除器
make_shared可通过参数列表传递参数给对象的构造函数std::shared_ptr<int> ptr = std::make_shared<int>(42)
make_shared对象不被引用时销毁,make_shared使控制块和对象分配在同一连续内存上,共享指针内存占用更少
template,function,bind
模板特化包含完全特例化和非完全
函数指针特例化包含返回值和参数特化
typeid().name获取模版参数类型
绑定器bind1st和bind2nd是将二元函数对象转为一元
bind1st固定第一参数值,bind2nd固定第二个
function用于绑定器,函数对象,lambda表达式的封装,便于调用
bind绑定器自动推演模板类型参数,参数可被参数占位符代替(20个)
lambda表达式[捕获变量](形参列表)->返回值{代码}
demo1
对象调用优化
结构图
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./pro
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
using namespace std;class Test
{public:Test(int data = 1):data(data){std::cout << "Test(int)" << std::endl;}~Test(){std::cout << "~Test()" << std::endl;}Test(const Test& t):data(t.data){std::cout << "Test(const T& t)" << std::endl;}Test &operator=(const Test& t){data = t.data;std::cout << "T &operator=" << std::endl;return *this; }int get_data() const{return data;}private:int data;
};//传引用没有构建和析构形参对象
Test print_data(const Test &t)
{std::cout << "data : " << t.get_data() << std::endl;//返回临时对象,可用于直接调用构造对象,Test t = Test(1); <==> Test t(1);//Test t(t.get_data()+1); return t;返回临时对象避免多次构造return Test(t.get_data()+1);
}//==========1==========
Test t0(1); //t0构造int main()
{std::cout << "=========3=========" << std::endl;Test t1(2); //t1构造print_data(t1);std::cout << "==================" << std::endl;std::cout << "=========4=========" << std::endl;Test t2 = t1; //t2赋值构造print_data(t2);std::cout << "==================" << std::endl;std::cout << "=========5=========" << std::endl;Test t3(t1); //t3拷贝构造print_data(t3);std::cout << "==================" << std::endl;std::cout << "========6=========" << std::endl;static Test t4 = Test(3); //t4构造<==>Test T4(3);print_data(t4);std::cout << "==================" << std::endl;//临时量语句结束析构std::cout << "========7==========" << std::endl;t2 = (Test)4; //构造临时量(Test(4)),用临时量赋值构造t2print_data(t2);std::cout << "==================" << std::endl;std::cout << "========8==========" << std::endl;t2 = 5; //构造临时量(Test(5)),用临时量赋值构造t2print_data(t2);std::cout << "==================" << std::endl;std::cout << "========9==========" << std::endl;const Test &t6 = Test(6); //构造临时量(Test(6))作为常量构造t2Test t7 = print_data(t6); //返回临时对象,可用于直接调用构造对象,Test t = Test(1); <==> Test t(1);print_data(t7);//Test *t8 = &Test(8); //指针指向临时量,语句结束后临时量析构,指针无法使用std::cout << "==================" << std::endl;//析构顺序:t7,t6,t4,t3,t2,t1,t5,t0return 0;
}//==========2==========
Test t5(5); //t5构造
结果示例
demo2
左值右值
结构图
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./pro
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
#include <cstring>class String
{public:String(const char *str = nullptr){std::cout << "String(str)" << std::endl;if(str == nullptr){ptr = new char('\0');}else{ptr = new char[strlen(str)+1];strcpy(ptr,str);}}~String(){std::cout << "~String()" << std::endl;delete[] ptr;ptr = nullptr;}String(const String& str){std::cout << "String(&)" << std::endl;ptr = new char[strlen(str.ptr)+1];strcpy(ptr,str.ptr);}String(String&& str){std::cout << "String(&&)" << std::endl;ptr = str.ptr;str.ptr = nullptr;}String& operator=(String& str){std::cout << "operator=(&)" << std::endl;if (this == &str) return *this;delete[] ptr;ptr = new char[strlen(str.ptr) + 1];strcpy(ptr, str.ptr);return *this;}String& operator=(String&& str){std::cout << "operator=(&&)" << std::endl;if(this == &str)return *this;delete[] ptr;ptr = str.ptr;str.ptr = nullptr;return *this;}const char *c_str() const{return ptr;}private:char *ptr;
};void print_str(const String& str)
{printf("%s\n",str.c_str());
}int main()
{String s0;print_str(s0);String s1("hello word");print_str(s1);String s2 = s1;print_str(s2);String s3(s1);print_str(s3);String s4(std::move(s1)); //此后s1.ptr为nullptrprint_str(s4);s0 = s2;print_str(s2);s0 = String("hello word");print_str(s0);return 0;
}
结果示例
demon3
move,forward
结构图
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./pro
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
using namespace std;template<typename T>
void fun(T& num)
{std::cout << "&" << std::endl;
}template<typename T>
void fun(const T& num)
{std::cout << "const &" << std::endl;
}template<typename T>
void fun(T&& num)
{std::cout << "&&" << std::endl;
}template<typename T>
void fun(const T&& num)
{std::cout << "const &&" << std::endl;
}void fun_r(int& num)
{std::cout << "&" << std::endl;
}void fun_r(const int& num)
{std::cout << "const &" << std::endl;
}void fun_r(int&& num)
{std::cout << "&&" << std::endl;
}void fun_r(const int&& num)
{std::cout << "const &&" << std::endl;
}template<typename T>
void fun_rr(T&& num)
{fun_r(num);
}template<typename T>
void fun_rrr(T&& num)
{fun_r(forward<T>(num));
}int main()
{int a = 1;const int b = 1;fun<int>(a);fun<int>(10);fun<int>(b);fun<int>(std::move(b));fun_rr(a);fun_rr(10);fun_rr(b);fun_rr(std::move(b));fun_rrr(a);fun_rrr(10);fun_rrr(b);fun_rrr(std::move(b));return 0;
}
结果示例
demo4
智能指针
结构图
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./pro
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
#include <memory>
#include <thread>
#include <functional>//自定义智能指针
template<typename T>
class UserDefineSmartPointer
{public:UserDefineSmartPointer(T *ptr = nullptr):ptr(ptr) {std::cout << "UserDefineSmartPointer()" << std::endl;}~UserDefineSmartPointer() {std::cout << "~UserDefineSmartPointer()" << std::endl;delete ptr;}private:T *ptr;
};template<typename T>
class UserDefineSharePtr
{public:UserDefineSharePtr(T *ptr = nullptr):ptr(ptr),use_count(new int(1)){std::cout << "UserDefineSharePtr()" << std::endl;};UserDefineSharePtr(const UserDefineSharePtr<T> &src):ptr(src.ptr),use_count(src.use_count){++(*use_count);std::cout << "UserDefineSharePtr(const UserDefineSharePtr<T> &src)" << std::endl;}UserDefineSharePtr<T>& operator=(const UserDefineSharePtr<T> &src){if(this == &src)return *this;++(*src.use_count);ptr = src.ptr;use_count = src.use_count;std::cout << "operator=(const UserDefineSharePtr<T> &src)" << std::endl;}const T& u_count() const{return *use_count;}const UserDefineSharePtr<T>* operator->(){return this;}const int operator*(){return *ptr;}~UserDefineSharePtr(){--(*use_count);if(*use_count == 0){delete ptr;ptr = nullptr;delete use_count; use_count = nullptr;}std::cout << "~UserDefineSharePtr()" << std::endl;}private:int *use_count;T *ptr;
};class A;
class B;class A
{public:A(){std::cout << "A()" << std::endl;}~A(){std::cout << "~A()" << std::endl;}std::weak_ptr<B> pb;
};class B
{public:B(){std::cout << "B()" << std::endl;}~B(){std::cout << "~B()" << std::endl;}std::weak_ptr<A> pa;
};void proc(const std::weak_ptr<int> p, const int *d)
{std::this_thread::sleep_for(std::chrono::seconds(2));std::shared_ptr<int> s = p.lock();if(s == nullptr || d == nullptr){std::cout << "*num:" << *s << std::endl;std::cout << "resource relase" << std::endl;return;}std::cout << "*num:" << *s << std::endl;std::cout << "*data:" << *d << std::endl;
}template<typename T>
class Deletor
{public:void operator()(T *ptr){std::cout << "Deletor()" << std::endl;delete [] ptr;}
};class Test
{public:Test() {}Test(int data){std::cout << "data:" << data << std::endl;}~Test(){}
};int main()
{//自定义智能指针UserDefineSmartPointer<int> p(new int(27));//auto_ptr不带引用计数且为浅拷贝,拷贝后前一资源置空std::auto_ptr<int> p1(new int(27));std::auto_ptr<int> p2 = p1;//std::cout << "*p1:" << *p1 << std::endl;std::cout << "*p2:" << *p2 << std::endl;//unique_ptr独占资源且不带引用计数//两指针指向同一资源,编译报错即拷贝构造和赋值构造为为private或deletestd::unique_ptr<int> p3(new int(27));std::unique_ptr<int> p4;//p4 = p3;std::cout << "*p3:" << *p3 << std::endl;//unique_ptr可移动构造把资源转交给另一指针,前一指针失效std::unique_ptr<int> p5 = std::move(p3);//std::cout << "*p3:" << *p3 << std::endl;std::cout << "*p5:" << *p5 << std::endl;//自定义share_ptrUserDefineSharePtr<int> p6(new int(27));UserDefineSharePtr<int> p7(p6);UserDefineSharePtr<int> p8 = p6;UserDefineSharePtr<int> p9;p9 = p6;std::cout << "*p6:" << *p6 << std::endl;std::cout << "*p7:" << *p7 << std::endl;std::cout << "*p8:" << *p8 << std::endl;std::cout << "*p9:" << *p9 << std::endl;std::cout << "u_count:" << p9->u_count() << std::endl;//定义对象用强指针shared_ptr,引用对象用弱指针weak_ptr解决交叉引用资源泄露{std::shared_ptr<A> pa(new A());std::shared_ptr<B> pb(new B());pa->pb = pb;pb->pa = pa;}//多线程访问共享资源时share_ptr定义资源,线程中传入weak_ptr提权访问资源,提权失败则资源被占用或释放,保证资源访问安全std::shared_ptr<int> num(new int(27));int *data = new int(27);std::thread t(proc,std::weak_ptr<int>(num),data);delete data;data == nullptr;t.join();//std::function<返回值类型(传入参数类型)> 方法名,lambda + function可用于实现删除器std::unique_ptr<int,Deletor<int>> ar(new int[27],Deletor<int>());std::unique_ptr<FILE,std::function<void (FILE*)>> f(fopen("data.txt", "w"),[](FILE *p)->void { fclose(p);std::cout << "fclose()" << std::endl;});//make_shared对象不被引用时销毁,make_shared使控制块和对象分配在同一连续内存上,共享指针内存占用更少auto tmp = std::make_shared<Test>(12);return 0;
}
结果示例
demo5
template,bind,function
结构图
run.sh
#!/bin/bashif [ -f ./Makefile ]
thenmake clean
ficmake .makeecho "---------------------------------"./pro
CMakeLists.txt
CMAKE_MINIMUM_REQUIRED(VERSION 3.28) #最低版本要求SET(CMAKE_CXX_COMPILER "g++-11") #设置g++编译器PROJECT(CLASS) #设置工程名MESSAGE(STATUS "CPP test") #打印消息ADD_EXECUTABLE(pro test.cpp) #生成可执行文件
clean.sh
rm -rf CMakeCache.txt CMakeFiles Makefile cmake_install.cmake *.o pro test test.dis
test.cpp
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <thread>template<typename T>
void func1(T t)
{std::cout << "func(T t):" << typeid(T).name() << std::endl;
}template<typename R,typename A1,typename A2>
void func2(R(*f)(A1,A2))
{std::cout << "func1<R(*f)(A1,A2)>" << std::endl;std::cout << "R:" << typeid(R).name() << std::endl;std::cout << "A1:" << typeid(A1).name() << std::endl;std::cout << "A2:" << typeid(A2).name() << std::endl;
}struct Test
{int sum(int a,int b) {return a + b;}
};template<typename T,typename R,typename A1,typename A2>
void func3(R(T::*f)(A1,A2))
{std::cout << "func1<R(T::*f)(A1,A2)>" << std::endl;std::cout << "T:" << typeid(T).name() << std::endl;std::cout << "R:" << typeid(R).name() << std::endl;std::cout << "A1:" << typeid(A1).name() << std::endl;std::cout << "A2:" << typeid(A2).name() << std::endl;
}int sum(int a, int b)
{return a + b;
}template<typename Iterator,typename Compare>
Iterator Find_if(Iterator first,Iterator last,Compare com)
{for( ;first != last; first++){if(com(*first))return first;}return last;}template<typename Compare,typename T>
class Bind1st
{public:Bind1st(Compare com,T value):com(com),value(value){}bool operator()(const T&second){return com(value,second);}private:Compare com;T value;
};template<typename Compare,typename T>
class Bind2st
{public:Bind2st(Compare com,T value):com(com),value(value){}bool operator()(const T& first){return com(first,value);}private:Compare com;T value;
};template<typename T>
void print_vec(T &t)
{for (auto a : t)std::cout << a << " ";std::cout << std::endl;
}template<typename T>
class Great
{public:bool operator()(const T& first,const T& second){return first > second;}
};template<typename T>
class Less
{public:bool operator()(const T& first,const T& second){return first < second;}
};template<typename T>
class Function{};template<typename R,typename... A>
class Function<R(A...)>
{public:using FUNC = R(*)(A...);Function(FUNC func):func(func){}R operator()(A... arg){return func(arg...);}private:FUNC func;};//子线程
class Thread
{public:Thread(std::function<void()> func):func(func){}std::thread start(){std::thread t(func);return t;}private:std::function<void()> func;
};//线程池
class ThreadPool
{public:ThreadPool(){}//释放子线程对象资源~ThreadPool(){for(int i = 0; i < t_pool.size(); i++)delete t_pool[i];}void start_pool(int size){//构建子线程对象for(int i = 0; i < size; i++)t_pool.push_back(new Thread(std::bind(&ThreadPool::RunThread,this,i)));//开启子线程,存储子线程句柄for(int i = 0; i < size; i++)t_handler.push_back(t_pool[i]->start());//子线程资源回收for(std::thread &t : t_handler)t.join();}private:std::vector<Thread*> t_pool;std::vector<std::thread> t_handler;//子线程函数入口void RunThread(int id){std::cout << "Thread id:" << id << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));}
};int main()
{/**模板特化包含完全特例化和非完全*模版被调用顺序:非特化->...->全特化*函数指针特例化包含返回值和参数特化*typeid().name获取模版参数类型*/func1(27);func1("cxb");func1(sum);func2(sum);func3(&Test::sum);/**绑定器bind1st和bind2nd是将二元函数对象转为一元*bind1st固定第一参数值,bind2nd固定第二个*/std::vector<int> v;for(int i = 0; i < 10; i++)v.push_back(rand()%100);print_vec<std::vector<int>>(v);std::sort(v.begin(),v.end(),Great<int>());print_vec<std::vector<int>>(v);auto it = Find_if(v.begin(),v.end(),Bind1st(Great<int>(),50));if(it != v.end())v.insert(it,100);print_vec<std::vector<int>>(v);auto it1 = Find_if(v.begin(),v.end(),Bind2st(Less<int>(),30));if(it1 != v.end())v.insert(it1,100);print_vec<std::vector<int>>(v);/**function用于绑定器,函数对象,lambda表达式的封装,便于调用*bind绑定器自动推演模板类型参数,参数可被参数占位符代替(20个)*/Function<int(int,int)> s = sum;std::cout << "1 + 2:" << s(1,2) << std::endl;Test t1;std::function<int(Test*,int,int)> s1 = &Test::sum;std::cout << "1 + 2:" << s1(&t1,1,2) << std::endl;std::function<int(int,int)> l = [](int a, int b)->int{return a + b;};std::cout << "a + b:" << l(1,2) << std::endl;std::cout << "1 + 2:" << std::bind(sum,1,2)() << std::endl;std::cout << "1 + 2:" << std::bind(sum,std::placeholders::_1,std::placeholders::_2)(1,2) << std::endl;auto b = std::bind(&Test::sum,Test(),std::placeholders::_1,std::placeholders::_2);std::cout << "1 + 2:" << b(1,2) << std::endl;auto b1 = std::bind(&Test::sum,t1,std::placeholders::_1,std::placeholders::_2);std::cout << "1 + 2:" << b1(1,2) << std::endl;std::cout << "1 + 2:" << std::bind([](int a, int b)->int{return a + b;},1,2)() << std::endl;//function + bind => thread poolThreadPool pool;pool.start_pool(10);return 0;
}
结果示例