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; }
};
template
class RefCnt
{
private:
_Ty* mptr;
int ref;
public:
RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {}
~RefCnt() {}
};
template
class 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; }
};
template
class RefCnt
{
private:
_Ty* mptr;
int ref;
public:
RefCnt(_Ty* p = nullptr) :mptr(p), ref(mptr != nullptr) {}
~RefCnt() {}
};
template
class 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; }
};
//处理一个对象的删除器
template
class MyDeletor
{
public:
//MyDeletor() = default;
MyDeletor() {}
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete ptr;
}
}
};
//处理一组对象的删除器
template
class MyDeletor<_Ty[]>
{
public:
MyDeletor() = default;
void operator()(_Ty* ptr) const
{
if (ptr != nullptr)
{
delete[]ptr;
}
}
};
//引用计数
template
class 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);
}
};
//处理一组对象
template
class 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];
}
};



