Smart pointer
1.shared pointer
读线程安全,写需要加锁
shared pointer允许多个指针指向某个内存区域
以下为简单实现
class Counter{
private:
uint64_t cnt=0;
public:
Counter():cnt(0){}
Counter(const Counter& c)=delete;
Counter& operator=(const Counter& c)=delete;
~Counter(){}
void reset(){
this->cnt=0;
}
uint64_t get(){
return this->cnt;
}
void operator++(){
this->cnt++;
}
void operator++(int){
this->cnt++;
}
void operator--(){
this->cnt--;
}
void operator--(int){
this->cnt--;
}
friend ofstream& operator<<(ofstream& out,const Counter& c){
out<<c.cnt<<'\n';
return out;
}
};
template<typename T>
class Shared_ptr{
private:
Counter* counter;
T* ptr;
public:
explicit Shared_ptr(T* ptr=nullptr){
this->counter=new Counter();
this->ptr=ptr;
(*this->counter)++;
}
Shared_ptr(Shared_ptr<T>& sp){
this->counter=sp.counter;
this->ptr=sp.ptr;
(*this->counter)++;
}
T* get(){
return this->ptr;
}
uint64_t get_cnt(){
return this->counter->get();
}
T& operator*(){
return *this->ptr;
}
T* operator->(){
return this->ptr;
}
~Shared_ptr(){
(*counter)--;
if(this->counter->get()==0){
delete counter;
delete this->ptr;
}
}
friend ostream& operator<<(ostream& out,Shared_ptr<T>&ptr){//watch out for the &,if not then call Shared_ptr(Shared_ptr<T>& sp)
out<<"address is"<<ptr.get()<<'\n';
out<<"counter is"<<ptr.get_cnt()<<'\n';
return out;
}
};
2.unique_ptr
没有构造函数,所以不支持普通的拷贝和赋值操作
不允许copy和赋值操作
unique具有唯一性,对指向的对象值存在唯一的unique_ptr。unique_ptr不可复制,赋值,但是move()可以转换对象的所有权,局部变量的返回值除外。与shared_ptr相比,若自定义删除器,需要在声明处指定删除器类型,而shared不需要,shared自定义删除器只需要指定删除器对象即可,在赋值时,可以随意赋值,删除器对象也会被赋值给新的对象。
3. weak_ptr
1.weak_ptr只能从shared_ptr对象构建。
2.weak_ptr并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。当weak_ptr所指向的对象因为shared_ptr计数器为0而被释放后,那么weak_ptr的lock方法将返回空。
3.weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。
4.提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空“shared_ptr),如果返回shared_ptr,那么计数器会加1.
解决了如下问题
1 当你想使用对象,但是并不管理对象,并且在需要时可以返回对象的shared_ptr时,则使用
2.解决shared_ptr的循环引用问题
class A;
class B{
public:
~B() {
std::cout << "B destory, a_ptr use_count:" << a_ptr.use_count() << "\n";
}
std::shared_ptr<A> a_ptr;
};
class A{
public:
~A() {
std::cout << "A destory, b_ptr use_count:" << b_ptr.use_count() << "\n";
}
std::shared_ptr<B> b_ptr;
};
int main(){
shared_ptr<int>p1(new int(3));
shared_ptr<int>p2(p1);
weak_ptr<int>pp1(p1);
cout<<pp1.use_count()<<'\n';
p2.reset();
cout<<pp1.use_count()<<'\n';
cout<<*pp1.lock()<<'\n';
p1.reset();
cout<<pp1.use_count()<<'\n';
cout<<pp1.expired()<<'\n';
std::shared_ptr<A> a(new A());
std::shared_ptr<B> b(new B());
a->b_ptr=b;
b->a_ptr=a;
std::cout << "A:" << a.use_count() << "\n";
std::cout << "B:" << b.use_count() << "\n";
return 0;
}
4.auto ptr
被废弃,主要支持以下功能
1.支持拷贝构造
2.支持赋值拷贝
3.支持operator->/operator*解引用
4.支持指针变量重置
5.保证指针持有者唯一
会有很多所有权转移的问题,比如如下的代码
std::auto_ptr<People> one = peoples[5];
这会把所有权进行交换,这是因为auto ptr实现了=,然后所有权就交换了
auto_ptr 可以赋值拷贝,复制拷贝后所有权转移;unqiue_ptr 无拷贝赋值语义,但实现了move 语义;
auto_ptr 对象不能管理数组(析构调用 delete),unique_ptr 可以管理数组(析构调用 delete[] );
Cast
static_cast
1.本质上是C强制转换的替代品,因为C的强制转换不好找,所以采用static_cast
2.对于C风格的强制转换来说,假如你把一个char强制转换成int\,这在C里面是可以实现的,但是运行的时候是会出错的,但是如果你使用static_cast,那么预编译的时候就会出错,让你没法编译惹
3.对于私有继承基类的子类来说,是不允许转换为基类指针的,但是用C强制转换可以,所以我们需要用static_cast来在预编译的时候发现错误
4.有时候,假如两个子类都继承同一个基类,你分别把该两个子类转换为基类,然后把拿到的转换为另一个子类,这样做在static_cast的时候可以过编译,所以我们在这种情况下不该使用它
5.处理void*的时候,记得用static_cast!
class Int{
private:
int x;
public:
Int(int a):x(a){
cout<<"call contructor!\n";
}
operator string(){
cout<<"call operator!\n";
return to_string(this->x);
}
int value(){
return this->x;
}
friend ostream& operator<<(ostream& out,Int& a){
out<<a.x<<'\n';
return out;
}
};
class Dad{
};
class Son:private Dad{
};
class Son_1:public Dad{
};
class Son_2:public Dad{
};
int main(){
float a_f=1.1;
int a_i=static_cast<int>(a_f);
assert(a_i==1);
Int obj(3);
cout<<obj<<'\n';
string obj_str=static_cast<string>(obj);
assert(obj_str=="3");
obj=static_cast<Int>(9);
assert(obj.value()==9);
int* b_int=new int;
char* b_char=new char;
//b_int=(int*)(b_char);//could pass,but wrong in runing
// b_int=static_cast<int*>(b_char);//fail since static_cast would check!
Son s;
//Dad* d=(Dad*)&s;//could pass wrong in runing since it is private inherient
//Dad* d=static_cast<Dad*>(&s);//could not pass unless it is public
Son_1 s1;
Son_2 s2;
Dad* d1=static_cast<Dad*>(&s1);
Dad* d2=static_cast<Dad*>(&s2);
Son_2* s22=static_cast<Son_2*>(d1);//should never use static_cast!
Son_1* s11=static_cast<Son_1*>(d2);
int i=10;
void* ptr=static_cast<void*>(&i);//always use static_cast
int* new_i=static_cast<int*>(ptr);
return 0;
}
2. dynamic cast
1.dynamic_cast是用于处理static_cast的上一个问题的
2.用于在正确的时候对基类向子类进行cast
3.需要多态的特性才能进行使用(至少有一个virtual function)
4.runtime check 所以性能你懂的
5.如果转换的新类型是引用类型,throw一个错误
class Dad{
virtual void print(){
cout<<"I am a dad\n";
}
};
class Son:public Dad{
void print()override{
cout<<"I am a son\n";
}
};
class Daughter:public Dad{
void print()override{
cout<<"I am a Daughter!\n";
}
};
int main(){
Son son1;
Dad* d=dynamic_cast<Dad*>(&son1);
assert(d!=nullptr);
Daughter* dau=dynamic_cast<Daughter*>(d);
assert(dau==nullptr);
try{
Daughter& dd=dynamic_cast<Daughter&>(son1);
}catch(std::exception& e){
std::cout<<e.what()<<"wrong!"<<'\n';
}
return 0;
}
3. reinterpret_cast
1.用于对某个结构体的重interpret
2.需要很小心的使用
3.用于位的重定义
class Man{
public:
void say_man(){
cout<<"I am a man\n";
}
};
class Woman{
public:
void say_woman(){
cout<<"I am a woman\n";
}
};
struct node{
int x,y;
char c;
bool b;
};
int main(){
Man* m=new Man;
Woman* w=new Woman;
m->say_man();
Man* new_man=reinterpret_cast<Man*>(w);//should not use it!
new_man->say_man();
//when you should use re_interpret_cast
node s;
s.y=1;s.c='a';s.x=2;s.b=false;
int* p=reinterpret_cast<int*>(&s);
cout<<*p<<'\n';
++p;
cout<<*p<<'\n';
++p;
cout<<*(reinterpret_cast<char*>(p))<<'\n';
return 0;
}
4.const_cast
用于删除 const、volatile 和 __unaligned 特性(如将 const int 类型转换为 int 类型 )
需要原数据不是constant
另一个用法是当你需要往某个需要变量的函数里传constant的时候,需要用const_cast来取消constant
void transfer(int* x){
cout<<"1\n";
}
int main(){
const int a=1;
const int* b=&a;
int* c=const_cast<int*>(b);// now removed the const
*c=2;//invalid and undefine behavior, should not use!
cout<<a<<'\n';//would not change,since compiler would directly write the constant value for print
int aa=1;
const int* bb=&aa;
int* cc=const_cast<int*>(bb);
*cc=3;
cout<<aa<<'\n';
const int v=1;
const int* pv=&v;
transfer(const_cast<int*>(pv));//ok
//transfer(pv);//panic!
return 0;
}
shared_ptr的问题
#include <bits/stdc++.h>
using namespace std;
class A{
public:
A(){};
A(int a): age(a) {};
~A(){};
private:
int age;
};
int main() {
A *a = new A(10);
shared_ptr<A> p1(a);
shared_ptr<A> p2(a);
}
当p1和p2超出作用域被销毁时,仍旧不会销毁,这个时候use_cnt都是1,我们需要这样修复
shared_ptr<A> p1(new A(10));
shared_ptr<A> p2(p1);
可以直接构造一个weak_ptr吗?
可以构造一个 weak_ptr 对象,但是需要注意它所引用的对象必须已经被一个 shared_ptr 管理。这是因为 weak_ptr 并不拥有资源,它只是对一个 shared_ptr 所管理的对象进行弱引用,可以用于观察这个对象的状态,但是并不会增加资源的引用计数。
std::move
1.强制转换左值为右值引用
std::string str = "Hello";
std::string&& rref = std::move(str);
2.使用移动语义进行赋值操作
std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2;
v2 = std::move(v1);
3.使用移动语义进行参数传递
void func(std::vector<int>&& v);
std::vector<int> v = {1, 2, 3};
func(std::move(v));