LOADING

加载过慢请开启缓存 浏览器默认开启

C++ 笔记(3)—— Effective Modern C++ (3-6 章)

2024/5/29 Language C++

Item 18 —— std::unique_ptr

std::unique_ptr 支持使用自定义的析构函数,可以传入一个 lambda 函数:

auto delFunc = [](auto* v) {
    std::cout << "Deconstruct for value: " << *v;
};
std::unique_ptr<int, decltype(delFunc)> ptr(new int{123}, delFunc);

这里 decltype 将再次发挥作用。注意,与 std::shared_ptr 不同,这个自定义析构函数的类型是会绑定到 std::unique_ptr 上的(参见模板第二个参数)。

Item 19 —— std::shared_ptr

std::shared_ptr 会额外维护一个控制块:

这个控制块位于堆上。在执行 move 操作的时候,控制块会沿用。当一个 std::shared_ptr 移动构造一个新的 std::shared_ptr 的时候,ref_cnt 不会增加(会将原来的设置为 nullptr)。

不能用一个裸指针初始化多个 std::shared_ptr,这会导致多个控制块,执行多次析构,造成未定义结果

std::shared_ptr 还支持对于每个实例都使用不同的自定义析构函数函数。如果使用了自定义析构函数,就无法用 std::make_shared 生成对应 std::shared_ptr 对象。与 std::unique_ptr 不同,自定义函数不会体现到类型上。
例如:

std::shared_ptr<int> ptr(new int{123}, delFunc);

有时候我们希望,对于一个对象 std::shared_ptr<Object>,我们希望在 Object 的成员函数中创建一个新的,指向自己(this)的 std::shared_ptr<Object>

class Object : public std::enable_shared_from_this<Object> {
   public:
    static std::shared_ptr<Object> Create(int val) {
        return std::shared_ptr<Object>(new Object(val));
    }
    std::shared_ptr<Object> CloneInner() { return shared_from_this(); }
    inline int Val() const { return val; }

    ~Object() { std::cout << "Deconstruct called." << std::endl; }

   private:
    int val;

    // shared_from_this 必须基于已有的 std::shared_ptr 对象。
    // 设置为 private 以防止用户构造一个裸露对象并调用 shared_from_this。
    explicit Object(int val) : val(val) {}
};

int main() {
    auto p = Object::Create(233);
    std::cout << "Value 1: " << p->Val() << std::endl;
    std::cout << "Reference Count: " << p.use_count() << std::endl;

    auto p2 = p->CloneInner();
    std::cout << "Value 2: " << p2->Val() << std::endl;

    std::cout << "Reference Count: " << p2.use_count() << std::endl;
}