1.主函数中的两行代码都可以创建Object类型实例
class Object{private: int value;public: Object(int x = 0) :value(x) { cout << "Object" << endl; } ~Object() { cout << "~Object" << endl; }};int main(){ std::shared_ptr
但是它们是有区别的,这两种方式的构建活动是不一样的
对于第一种方式来说,op1有一个ptr指针和一个删除器(mDeletor),ptr指针指向引用计数对象(RefCnt),引用计数对象有mptr指针和引用计数(ref),mptr直指向Object对象,Object对象的value域的值为10,在这个过程中在堆区的构建new了两次
对于第二种方式来说进行了一些的优化,它能够计算出Object的大小和引用计数对象的大小,直接一次开辟够Object对象和引用计数大小一样的空间,引用计数对象的mptr指针指向Object对象,在这个过程中在堆区的构建只new一次
这两种结构有什么区别呢?
在第一种方式中释放对象需要释放两次,而在第二种方式种释放对象只需要释放一次,而用第二种方式创建的对象在析构的时候也更加的复杂,需要更深入的编程
2.画出下面程序的内存分布图
class Object{private: int value;public: Object(int x = 0) :value(x) { cout << "Object" << endl; } ~Object() { cout << "~Object" << endl; }};templateclass RefCnt{private: _Ty* mptr; int ref;public: RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {} ~RefCnt() {}};templateclass my_shared_ptr{private: RefCnt<_Ty>* ptr;public: my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr) { if (p != nullptr) { ptr = new RefCnt(p); } }};int main(){ std::shared_ptr sp1(new Object(10)); std::shared_ptr sp2;return 0;}
3.判断下面程序的引用计数各是多少?
class Object{private: int value;public: Object(int x = 0) :value(x) { cout << "Object" << endl; } ~Object() { cout << "~Object" << endl; }};templateclass RefCnt{private: _Ty* mptr; int ref;public: RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {} ~RefCnt() {}};templateclass my_shared_ptr{private: RefCnt<_Ty>* ptr;public: my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr) { if (p != nullptr) { ptr = new RefCnt(p); } }};int main(){ std::shared_ptr sp1(new Object(10)); std::shared_ptr sp2 = std::make_shared(20); std::shared_ptr sp3; std::shared_ptr sp4(sp1); cout << sp1.use_count() << endl;//2 cout << sp2.use_count() << endl;//1 cout << sp3.use_count() << endl;//0 cout << sp4.use_count() << endl;//2 return 0;}
4.拷贝构造函数和赋值函数执行完以后,两个对象是一模一样的,而移动构造和移动赋值的目的就是把A对象对资源的拥有权交给B对象,而A对象没有对资源的拥有权,通俗来讲就是资源转移了
int main(){Object obj1;//普通构造Object obj2(obj1);//拷贝构造Object obj3(std::move(obj1));//移动构造obj1 = obj2;//普通赋值obj1 = std::move(obj2);//移动赋值return 0;}
5.在C11标准中,有6个默认的函数,如果不写,编译器会自动为我们加上缺省的函数,有构造函数、析构函数、拷贝构造函数、赋值函数、对普通对象取地址符重载、对常对象取地址符重载,在C11标准以后,新增了移动构造和移动赋值,变成了8个默认的函数
class Object{private:int value;public://C11前Object() {}~Object() {}Object(const Object & src) {}Object& operator=(const Object& src) {}Object* operator&() { return this; }const Object* operator&() const { return this; }//C11后Object(Object&& src) {} //移动构造Object & operator=(Object && src) {} //移动赋值};
6.面试的智能指针常问
7.循环引用
会导致两个对象都不能析构,因为循环引用会导致两个对象的引用计数都是2
class Child;class Parent{public:shared_ptr child;Parent() { cout << "Parent" << endl; }~Parent() { cout << "~Parent" << endl; }void hi() { cout << "Hello" << endl; }};class Child{public:shared_ptr parent;Child() { cout << "Child" << endl; }~Child() { cout << "~Child" << endl; }};void fun(){shared_ptr p = make_shared();shared_ptr c = make_shared();p->child = c;c->parent = p;c->parent->hi();}int main(){return 0;}
那么如何解决上面的问题呢?
答案:使用弱引用
8.对于引用计数ref,它的值不应该是一个整型值,因为整型值在多线程中进行自加自减时并没有安全性,因为它不是原子操作,但是可以通过引入头文件#include ,可以将int ref;替换成std::atomic(int) ref;这时使用ref进行加一减一或者和零值比较就具有原子性了,这样来说程序就相对安全一些
9.共享型智能指针全部代码
//Object对象class Object{private:int value;public:Object(int x = 0) :value(x) { cout << "Object" << endl; }~Object() { cout << "~Object" << endl; }};//处理一个对象的删除器templateclass MyDeletor{public://MyDeletor() = default;MyDeletor() {}void operator()(_Ty* ptr) const{if (ptr != nullptr){delete ptr;}}};//处理一组对象的删除器templateclass MyDeletor<_Ty[]>{public:MyDeletor() = default;void operator()(_Ty* ptr) const{if (ptr != nullptr){delete[]ptr;}}};//引用计数templateclass RefCnt{public:_Ty* mptr;//int ref;std::atomic_int ref;public:RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {}~RefCnt() {}};//处理单个对象template >class my_shared_ptr // thread;{private:RefCnt<_Ty>* ptr;_Dx mDeletor;public:my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr){if (p != nullptr){ptr = new RefCnt(p);}}my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr){if (ptr != nullptr){ptr->ref += 1;}}// my_shared_ptr op2(op1);my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr){_Y.ptr = nullptr;}// my_shared_ptr op2(std::move(op1));operator bool() const { return ptr != nullptr; }my_shared_ptr& operator=(const my_shared_ptr& _Y) // {if (this == &_Y || this->ptr == _Y.ptr) return *this;if (ptr != NULL && --ptr->ref == 0){mDeletor(ptr);}ptr = _Y.ptr;if (ptr != nullptr){ptr->ref += 1;}return *this;}my_shared_ptr& operator=(my_shared_ptr&& _Y) // move operator ={if (this == &_Y) return *this;if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr){this->ptr->ref -= 1;_Y.ptr = nullptr;return * this;}if (this->ptr != nullptr && --ptr->ref == 0){mDeletor(ptr);}ptr = _Y.ptr;_Y.ptr = nullptr;return *this;}void reset(_Ty* p = nullptr){if (this->ptr != nullptr && --this->ptr->ref == 0){mDeletor(ptr);}ptr = new RefCnt<_Ty>(p);}~my_shared_ptr(){if (this->ptr != nullptr && --this->ptr->ref == 0){mDeletor(ptr->mptr);delete ptr;}ptr = nullptr;}_Ty* get() const { return ptr->mptr; }_Ty& operator*() const{return *get();}_Ty* operator->() const{return get();}size_t use_count() const{if (this->ptr == nullptr) return 0;return this->ptr->ref;}void swap(my_shared_ptr& r){std::swap(this->ptr, r.ptr);}};//处理一组对象templateclass my_shared_ptr<_Ty[],_Dx>{private:RefCnt<_Ty>* ptr;_Dx mDeletor;public:my_shared_ptr(_Ty* p = nullptr) :ptr(nullptr){if (p != nullptr){ptr = new RefCnt(p);}}my_shared_ptr(const my_shared_ptr& _Y) :ptr(_Y.ptr){if (ptr != nullptr){ptr->ref += 1;}}// my_shared_ptr op2(op1);my_shared_ptr(my_shared_ptr&& _Y) :ptr(_Y.ptr){_Y.ptr = nullptr;}// my_shared_ptr op2(std::move(op1));operator bool() const { return ptr != nullptr; }my_shared_ptr& operator=(const my_shared_ptr& _Y) // {if (this == &_Y || this->ptr == _Y.ptr) return *this;if (ptr != NULL && --ptr->ref == 0){mDeletor(ptr->mptr);delete ptr;}ptr = _Y.ptr;if (ptr != nullptr){ptr->ref += 1;}return *this;}my_shared_ptr& operator=(my_shared_ptr&& _Y) // move operator ={if (this == &_Y) return *this;if (this->ptr == _Y.ptr && this->ptr != nullptr && _Y.ptr != nullptr){this->ptr->ref -= 1;_Y.ptr = nullptr;return * this;}if (this->ptr != nullptr && --ptr->ref == 0){mDeletor(ptr->mptr);delete ptr;}ptr = _Y.ptr;_Y.ptr = nullptr;return *this;}void reset(_Ty* p = nullptr){if (this->ptr != nullptr && --this->ptr->ref == 0){mDeletor(ptr->mptr);delete ptr;}ptr = new RefCnt<_Ty>(p);}~my_shared_ptr(){if (this->ptr != nullptr && --this->ptr->ref == 0){mDeletor(ptr->mptr);delete ptr;}ptr = nullptr;}_Ty* get() const { return ptr->mptr; }_Ty& operator*() const{return *get();}_Ty* operator->() const{return get();}size_t use_count() const{if (this->ptr == nullptr) return 0;return this->ptr->ref;}void swap(my_shared_ptr& r){std::swap(this->ptr, r.ptr);}_Ty& operator[](const int idx) const{return ptr->mptr[idx];}};