std::unique_ptr 阅读笔记

  • demo:
#include<memory>
#include<windows.h>
const wchar_t* const FILE_PATH = LR"(D:\temp\test.txt)";
#pragma optimize("",off)
struct HANDLEDeleter
{

	void operator()(HANDLE hHandle)const {
		if (hHandle != INVALID_HANDLE_VALUE && hHandle != NULL) {
			CloseHandle(hHandle);
		}
	}
};
using HANDL_UNIQUE_PTR = std::unique_ptr<void, HANDLEDeleter>;
int main()
{
	std::unique_ptr<HANDLE, HANDLEDeleter> hFile((void**) CreateFileW(FILE_PATH, GENERIC_READ, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, OPEN_ALWAYS, NULL));


	return 0;
}

整体的阅读思路,跟着effective modern c++ 走

条款18: 使用std::unique_ptr 管理具备专属所有权的资源

  • 阅读疑问1.

默认情况下,std::unique_ptr 和裸指针有着相同的尺寸,并且对于大多数的操作,它们都是精确执行了相同的指令。

std::unique_ptr的定义为:

// CLASS TEMPLATE unique_ptr SCALAR unique_ptr 模板类的定义,第二个参数没有??????有默认参数???,参见上面的模板参数
template <class _Ty, class _Dx /* = default_delete<_Ty> */>
class unique_ptr { // non-copyable pointer to an object
public:
    using pointer      = typename _Get_deleter_pointer_type<_Ty, remove_reference_t<_Dx>>::type;
    using element_type = _Ty;
    using deleter_type = _Dx;

    template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
    constexpr unique_ptr() noexcept : _Mypair(_Zero_then_variadic_args_t()) {}

    template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
    constexpr unique_ptr(nullptr_t) noexcept : _Mypair(_Zero_then_variadic_args_t()) {}

    unique_ptr& operator=(nullptr_t) noexcept {
        reset();
        return *this;
    }

    template <class _Dx2 = _Dx, _Unique_ptr_enable_default_t<_Dx2> = 0>
    explicit unique_ptr(pointer _Ptr) noexcept : _Mypair(_Zero_then_variadic_args_t(), _Ptr) {}

    template <class _Dx2 = _Dx, enable_if_t<is_constructible_v<_Dx2, const _Dx2&>, int> = 0>
    unique_ptr(pointer _Ptr, const _Dx& _Dt) noexcept : _Mypair(_One_then_variadic_args_t(), _Dt, _Ptr) {}

//.... 中间的一些函数声明
    unique_ptr(const unique_ptr&) = delete;
    unique_ptr& operator=(const unique_ptr&) = delete;

private:
    template <class, class>
    friend class unique_ptr;

    _Compressed_pair<_Dx, pointer> _Mypair;// 唯一的成员
};

我们可以观察到,std::unique_ptr 只有一个成员,而这个成员的类型_Compressed_pair 是个模板类,其第一个参数为deletor ,第二个参数为所管理的资源的类型

而上一节中,我们可以看到

emplate <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 { // store a pair of values, deriving from empty first,之所以这么搞,是因为如果单独将一个空的对象存储为值,将至少占1 字节空间,派生了,就没关系了

public:
    _Ty2 _Myval2;

    using _Mybase = _Ty1; // for visualization

    template <class... _Other2>
    constexpr explicit _Compressed_pair(_Zero_then_variadic_args_t, _Other2&&... _Val2) noexcept(
        conjunction_v<is_nothrow_default_constructible<_Ty1>, is_nothrow_constructible<_Ty2, _Other2...>>)
        : _Ty1(), _Myval2(_STD forward<_Other2>(_Val2)...) {}

    template <class _Other1, class... _Other2>
    constexpr _Compressed_pair(_One_then_variadic_args_t, _Other1&& _Val1, _Other2&&... _Val2) noexcept(
        conjunction_v<is_nothrow_constructible<_Ty1, _Other1>, is_nothrow_constructible<_Ty2, _Other2...>>)
        : _Ty1(_STD forward<_Other1>(_Val1)), _Myval2(_STD forward<_Other2>(_Val2)...) {}

    constexpr _Ty1& _Get_first() noexcept {
        return *this;
    }

    constexpr const _Ty1& _Get_first() const noexcept {
        return *this;
    }
};

_compressed_pair 类继承了_Ty1,而其,当这个delete 操作仅仅是个动作而没有一些成员信息的时候,其大小为0,_compressed_pair 就如其类名一样,压缩了存储“对象”+“删除动作”,时所需要的存储两个对象的未知。那可能这里有一个疑问,哪里存储了这样的一个delete 操作呢?答案就是:该std::unique_ptr 的类型,这样的一个编译时信息,提供了其delete 操作应该做的动作

  • 疑问2,对接口的自动析构,p119 ,ln2 指出,自定义析构器现身以后,情况有所不同,若析构器是函数指针,那么std::unique_ptr 的尺寸一般会增加一到两个字长(word)。若析构器是函数对象,则带来的尺寸变化取决于该函数对象中存储了多少状态。无状态的函数对象(例如,无捕获的lambda 表达式)不会浪费任何存储尺寸,这意味着当一个自定义析构器既可以用函数,又可以用无捕获的lambda 表达式来实现,lambda 表达式是更好的选择。
  1. 首先,std::function 对象最少40 字节,这个已经讨论过了(https://blog.csdn.net/qq_18218335/article/details/105498941),且其调用是通过了虚函数,速度会慢一点点

  2. 如果是函数指针,那必须有地方存储这样的一个函数地址,因此,也需要增加额外的大小,

  3. 如果是lambda ,其本质是一个编译器生成的类,因此,如果没有captre/context的话,继承其,就相当于上面的父类大小为0,结果是省内存(其调用逻辑,用编译时的类型信息表达出来了,这里我们应该可以很强烈的体会到c++ 种类型信息所起到的强大作用


using handleDeleter = [](HANDLE hHandle) {
	if (hHandle != INVALID_HANDLE_VALUE && hHandle != NULL) {
		CloseHandle(hHandle);
	}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值