智能指针

意义

智能指针简化资源的管理,从根本上消除资源(内存)泄露的可能;实质上是RAII资源管理功能的自然展现。

代码1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
enum class shape_type {
circle
,
triangle,
rectangle,

};
class shape { … };
class circle : public shape { … };
class triangle : public shape { … };
class rectangle : public shape { … };
shape* create_shape(shape_type type)
{

switch (type) {
case shape_type::circle:
return new circle(…);
case shape_type::triangle:
return new triangle(…);
case shape_type::rectangle:
return new rectangle(…);

}
}

为了确保在使用 create_shape 的返回值时不会发生内存泄漏

把这个返回值放到一个本地变量里,并确保其析构函数会删除该对象即可

1
2
3
4
5
6
7
8
9
10
11
class shape{};
class shape_wrapper{
private:
shape* ptr_;
public:
explicit shape_wrapper(shape* ptr=nullptr):ptr_(ptr){};
~shape_wrapper(){
delete ptr_;
}
shape* get() const{ return ptr_; }
};

该代码完成了智能指针的最基本功能: 对超出作用域的对象释放

但其面临的问题有3:

1.该类只适用于shape类

2.该类对象的行为不够像指针

3.拷贝该类对象会引发程序行为异常

PS:explicit 其作用是指定仅有一个参数或除第一个参数外其它参数均有默认值的类构造函数不能作为类型转化操作符被隐含的使用,防止该类的对象直接被对应内置类型隐式转化后赋值,从而规定这个构造函数必须被明确调用。

shape* ptr=nullptr: 是构造函数的参数列表,其中 shape* ptr 是一个名为 ptr 的指向 shape 类对象的指针参数,=nullptr 是为了提供一个默认参数值(空指针)

: ptr_(ptr): 这是构造函数的初始化列表,用于初始化成员变量。ptr_ 是类的成员变量,通过初始化列表将构造函数的参数 ptr 赋值给了成员变量 ptr_

代码2

模板化和易用性

要让这个类能够包装任意类型的指针,我们需要把它变成一个类模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
class smart_ptr
{
public:
explicit smart_ptr(T *ptr = nullptr)
: ptr_(ptr) {}
~smart_ptr()
{
delete ptr_;
}
T *get() const { return ptr_; }

private:
T *ptr_;
};

但是该类的行为与指针还是有点差异:

不能用*运算符解引用

不能用->运算符指向对象成员

不能像指针一样用在布尔表达式里

解决办法:添加成员函数

1
2
3
4
5
6
7
8
template <typename T>
class smart_ptr {
public:

T& operator*() const { return *ptr_; }
T* operator->() const { return ptr_; }
operator bool() const { return ptr_; }
}

代码3

拷贝构造和赋值

1
2
3
4
5
//声明指针类型(smart_ptr<shape>)+变量名(ptr1)+{指针值}
smart_ptr<shape>ptr1{create_shape(shape_type::circle)};
smart_ptr<shape> ptr2{ptr1};
//等价于以下语句
//smart_ptr<shape> ptr2 = ptr1;

对于第二行,究竟应当让编译时发生错误,还是可以有一个更合理的行为

可以理解为,由于第二行是调用拷贝构造函数的行为

有两种可能:

1.调用默认拷贝构造函数,可能导致错误

因为拷贝构造函数已经被删除(=delete),这将导致编译错误

2.调用自定义拷贝构造函数,可能有不同结果

先引入一下拷贝构造函数,一个空类,系统会默认给四个函数,构造、析构、拷贝构造函数和赋值运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Person {
private:
char* name; // 指向姓名的指针
public:
// 构造函数
Person(const char* n) {
name = new char[strlen(n) + 1];
strcpy(name, n);
}

// 拷贝构造函数
Person(const Person& other) {
name = new char[strlen(other.name) + 1];
strcpy(name, other.name);
}
...
};
int main()
{
Person person1("Alice");
Person person2 = person1; // 调用拷贝构造函数,复制 //person1 的内容到 person2
}

Person person2 = person1; 尝试创建一个新的 smart_ptr 对象 person2 并用 person1 的值进行初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

#include<iostream>

using namespace std;
template <typename T>
class smart_ptr
{
public:
explicit smart_ptr(T *ptr = nullptr):ptr_(ptr) {
cout<<"construct!"<<endl;
}

~smart_ptr()
{
cout<<"delete~"<<endl;
delete ptr_;
}
T *get() const { return ptr_; }


private:
T *ptr_;
};
int main()
{
//创建smart对象去管理int类型的指针
smart_ptr<int> ptr1(new int(42));
smart_ptr<int> ptr2=ptr1;
cout<<*ptr1.get()<<endl;
cout<<*ptr2.get()<<endl;
return 0;
}

construct!
42
42
delete~
delete~

首先尝试禁止拷贝

1
2
3
4
5
6
7
template <typename T>
class smart_ptr {

smart_ptr(const smart_ptr&)=delete;
smart_ptr& operator=(const smart_ptr&)=delete;

};

smart_ptr& operator=(const smart_ptr&)=delete;

导致默认拷贝构造函数调用失败

由于智能指针的目的就是减少对象的拷贝;且没有通用的方法可以通过基类的指针来构造出一个子类的对象

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2023-2025 是羽泪云诶
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信