本文主要探讨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 "---------------------------------"
./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)),用临时量赋值构造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 "---------------------------------"
./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为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 "---------------------------------"
./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/bash
if [ -f ./Makefile ]
then
make clean
fi
cmake .
make
echo "---------------------------------"
./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或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 "---------------------------------"
./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 pool
ThreadPool pool;
pool.start_pool(10);
return 0;
}
结果示例