C++理解(六)
- 其他
- 2025-09-12 11:27:01

本文主要探讨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/bash if [ -f ./Makefile ] then make clean fi cmake . make echo "---------------------------------" ./proCMakeLists.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.distest.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)),用临时量赋值构造t2 print_data(t2); std::cout << "==================" << std::endl; std::cout << "========8==========" << std::endl; t2 = 5; //构造临时量(Test(5)),用临时量赋值构造t2 print_data(t2); std::cout << "==================" << std::endl; std::cout << "========9==========" << std::endl; const Test &t6 = Test(6); //构造临时量(Test(6))作为常量构造t2 Test 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,t0 return 0; } //==========2========== Test t5(5); //t5构造结果示例
demo2
左值右值
结构图
run.sh
#!/bin/bash if [ -f ./Makefile ] then make clean fi cmake . make echo "---------------------------------" ./proCMakeLists.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.distest.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为nullptr print_str(s4); s0 = s2; print_str(s2); s0 = String("hello word"); print_str(s0); return 0; }结果示例
demon3
move,forward
结构图
run.sh
#!/bin/bash if [ -f ./Makefile ] then make clean fi cmake . make echo "---------------------------------" ./proCMakeLists.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.distest.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/bash if [ -f ./Makefile ] then make clean fi cmake . make echo "---------------------------------" ./proCMakeLists.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.distest.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或delete std::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_ptr UserDefineSharePtr<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/bash if [ -f ./Makefile ] then make clean fi cmake . make echo "---------------------------------" ./proCMakeLists.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.distest.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 pool ThreadPool pool; pool.start_pool(10); return 0; }结果示例