std::unique_ptr 如何在闭包上应用 EBO?

问题描述 投票:0回答:1
#include <memory>

#include <cstdio>

int main(){
    auto x1 = [](int *p){ delete(p); };

    auto ptr = std::unique_ptr<int, decltype(x1)>(new int{1},x1);

    printf("%zu\n", sizeof(ptr)); //  8, unexpected
}

带有 lambda 的类型的大小为 8

跟进这个问题:如果使用 lambda,std::unique_ptr 如何没有大小开销

我的结论是,EBO(空基类优化)通过继承空基类来避免增加对象大小

为此,让我们转到 Github 存储库以获取 unique_ptr 的 Microsoft STL 实现:

然后如果我们转到第 1229 行:

https://github.com/microsoft/STL/blob/master/stl/inc/memory#L1229

您可以看到以下帮助程序类型:

_Compressed_pair<_Dx, pointer> _Mypair;

该实现将指针和删除器存储在压缩对内。

在整个类代码中,您可以注意到 unique_ptr 使用 _Mypair 对象来引用数据和删除器。例如在析构函数中:

~unique_ptr() noexcept {
        if (_Mypair._Myval2) {
            _Mypair._Get_first()(_Mypair._Myval2); // call deleter
        }
    }

我们看一下代码:

这次我们要进入xmemory头了:

https://github.com/microsoft/STL/blob/master/stl/inc/xmemory#L1487

我们有两个模板专业化:

第一个:

type here// store a pair of values, deriving from empty first
template <class _Ty1, class _Ty2, bool = is_empty_v<_Ty1> && 
                                         !is_final_v<_Ty1>>
class _Compressed_pair final : private _Ty1 {
public:
    _Ty2 _Myval2;
    
    // ... the rest of impl

第二个:

// store a pair of values, not deriving from first
template <class _Ty1, class _Ty2>
class _Compressed_pair<_Ty1, _Ty2, false> final { 
public:
    _Ty1 _Myval1;
    _Ty2 _Myval2;
    
    // ... the rest of impl

压缩对非常简单,因为它只考虑第一个类型是否为空。我认为

std::unique_ptr<int, decltype(x1)>)
使用第一个,但在 C++20 之前,闭包类型没有(自 C++14 起)默认构造函数。,所以第一个中的
_Compressed_pair
派生了没有默认构造函数的基类,它如何创建实例
_Compressed_pair<_Dx, pointer> _Mypair;

如果删除了基类的构造函数,那么子类也无法构造对象。那么在C++20之前unique_ptr是如何在闭包上应用EBO的呢?

c++ c++17 c++14 smart-pointers unique-ptr
1个回答
0
投票

如果删除了基类的构造函数,那么子类也无法构造对象。

lambda 的默认构造函数被删除,但它仍然能够被复制/移动构造。

    static_assert(!std::is_default_constructible_v<decltype(x1)>); // different since C++20
    static_assert(std::is_move_constructible_v<decltype(x1)>);
    static_assert(std::is_copy_constructible_v<decltype(x1)>);

演示

_Compressed_pair
提供了一个构造函数,允许对
Ty_1
进行复制/移动初始化。

    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)...) {}

当您像这样构造 std::unique_ptr 时,您提供

x1
作为参数。

 auto ptr = std::unique_ptr<int, decltype(x1)>(new int{1},x1);

这就是

_Mypair
的构造方式。

© www.soinside.com 2019 - 2024. All rights reserved.