何时使用智能指针

这里是我对何时使用智能指针的思考🤔。

何时使用智能指针

智能指针一共有三个unique_ptr,shared_ptrweak_ptr。其中weak_ptr是为了弥补shared_ptr所造成的循环指向而诞生的,使用的场景很明确,所以不予讨论。

unique_ptr的意义是一个人独占的所有权,不可分享的所有权。而与之对立的shared_ptr则是可以共享的所有权
但是很多时候所有权这个东西的定义很模糊,比如说给函数式编程中的函数(不改变参数,也没有副作用)传递参数时,比如下面的sum函数:

1
2
template <typename T>
T Sum(const T& t1, const T& t2);

你说我这是将t1,t2的所有权给Sum函数了,这显然说不过去。但是你说我是和Sum函数共享这两个变量,好像也不太对。这里函数对于这两个变量的使用情况应该属于借用,借一下,用完就还给你的这种。
Rust将借用这种语义放在了语言里(通过编译器来进行安全性的保证)。而函数式编程则可以通过返回值返回处理后的结果(某种意义上也是借用,先获得所有权,然后创造个新的同类型东西给你,相当于给你原来的东西进行加工)。但是在OO思想中好像没有什么方法,这个时候使用unique_ptrshared_ptr就会显得很尴尬,所以我认为在这种所有权模糊不清的情况下应该直接使用裸指针。
有人说啊这里直接传递智能指针的引用不就行了,那如果是这样的情况呢:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class Entity {
public:
    // 这里的T应该是什么类型呢?
    T GetAttackComp() const { return attackable_; }
    T GetDefenceComp() const { return defencable_; }
    T GetHealComp() const { return healable_; }

private:
    unique_ptr<Component> attackable_;
    unique_ptr<Component> defencable_;
    unique_ptr<Component> healable_;
};

// 这里的T应该是什么类型呢?
void DoAttack(T attackComp) {
    // do your attack
}

对于ECS系统,Component应当被其Entity所拥有。这个时候我需要获得某个组件,显然我不能够返回unique_ptr<Component>,这样所有权就不再在Entity身上了。但是返回shared_ptr也是很荒唐的,因为Entity想要独占Component的所有权。
在调用DoAttack函数时同样是面临着借用的情况。而处理这种借用的情况我总结出了以下解决方法:

  1. 使用裸指针。因为所谓借用,就是借你的东西用一会,这个使用时间很短,使用的时间一定在变量生命周期之内的(即不会出现智能指针已经释放了而借用仍然存在的情况,如果出现这种情况,应当使用shared_ptr,因为shared_ptr就是在不知道多个操作中哪个操作何时结束的情况下用来延后指针释放的时间的)。
  2. 对于函数的借用,可以学习函数式编程,参数传递智能指针,返回值返回同样的类型。
updatedupdated2023-06-182023-06-18