中山市seo上词百度seo工作室
通常在面试中需要手撕实现的是shared_ptr,其主要特性是使用一个计数器进行对资源的管理。在面试中只需要简单要实现的以下功能:
- 引用计数:通过计数器跟踪指针被引用的次数
- 自动内存管理:当引用计数归零时自动释放内存
- 拷贝语义:支持深拷贝,增加引用计数
- 移动语义:支持资源所有权的转移
- 异常安全:移动操作使用noexcept保证安全性
- 操作符重载:支持常规指针的*和->操作
1、成员变量
也就是说在其中需要两个成员变量,一个是需要存储的指针,另一个是一个计数器。
那么计数器的类型是什么?
首先,该指向同一个资源的计数器值需要相同,可以同步对计数器的增加或减少。截至到这时有两种方式
1、指针
2、static。
那么他们有什么区别?static在泛型编程中每一个类型都共享这个变量,而同一个类型不一定只有一个资源。所以static不可行。也就是说是这样的
template <typename T>
class SmartPoint
{
private:T* prt;size_t* count;
};
2、计数器减少
由于拷贝构造和析构函数都有可能对计数器经行减少删除,所以将这一步封装成一个新的函数(记得是私有函数)。
void release() {if(--(*count) == 0){delete ptr;delete count;ptr = nullptr;count == nullptr;std::cout << "资源已经释放" << std::endl;}}
3、构造函数、析构函数
通常在智能指针构造函数中,我们都是传入一个new出来的指针交由智能指针管理或是不传参。且我们不希望指针在传入时出现隐式类型转换,所以使用explicit关键字
explicit SmartPoint(T* p = nullptr) :ptr(p),count(new size_t(1)){std::cout << "创建智能指针" << endl;}~SmartPoint(){if (count)release();}
4、拷贝构造函数、拷贝赋值运算符
在这两个中要注意的就是为了防止两个成员变量发生改变要使用const,以及拷贝赋值运算符需要返回*this(见Effective C++条款10:令operator=返回一个reference to *this)和this在拷贝赋值前需要先删除原先资源。
SmartPoint(const SmartPoint<T>& other):ptr(other.ptr), count(other.count){++(*count);std::cout << "拷贝构造智能指针" << (*count) << std::endl;}SmartPoint<T>& operator=(const SmartPoint<T>& other){if (this != &other){release();ptr = other.ptr;count = other.count;++(*count);std::cout << "拷贝赋值,计数" << *count << std::endl;}return *this;}
5、移动拷贝构造函数、移动拷贝赋值运算符
移动拷贝是对资源的直接移动,不会让计数器发生增加或者减少,因为传入的是右值,只需要将资源转移就行。
要注意的是容器重新分配时,使用移动而不是拷贝,前提是移动操作是noexcept的,否则会回退到拷贝,影响性能。
SmartPoint(SmartPoint<T>&& other) noexcept:ptr(other.ptr), count(other.count){other.ptr = nullptr;other.count = nullptr;}SmartPoint<T>& operator=(SmartPoint<T>&& other) noexcept {if (this != &other){release();ptr = other.ptr;count = other.count;other.ptr = nullptr;other.count = nullptr;}return *this;}
6、重载操作符
T& operator*() const { return *ptr; }T* operator->() const { return ptr; }size_t use_count() const { return count ? *count : 0; }
7、测试
// 示例使用
int main() {SmartPoint<int> p1(new int(42)); // 计数 1{SmartPoint<int> p2 = p1; // 拷贝构造,计数 2SmartPoint<int> p3;p3 = p2; // 拷贝赋值,计数 3std::cout << "数值: " << *p3 << "\n";} // p2/p3 析构,计数 1SmartPoint<int> p4 = std::move(p1); // 移动构造std::cout << "移动后计数: " << p4.use_count() << "\n";return 0;
}