【问题标题】:size of std::unique_ptr object with custom deleter (a lambda with capture by-ref)带有自定义删除器的 std::unique_ptr 对象的大小(带有按引用捕获的 lambda)
【发布时间】:2019-11-11 10:58:45
【问题描述】:

在下面的代码中,我有一个用于std::unique_ptr 的自定义删除器(使用通过引用捕获的 lambda)。我预计std::unique_ptr 对象的大小应该与默认删除器(即使用运算符删除)的大小相同,因为捕获是通过引用进行的。我知道无状态函子和 lambdas(没有捕获)不会产生大小损失,那么为什么 lambdas 引用捕获会产生大小损失?提前感谢您的解释。

#include <iostream>
#include <memory>

class X{};

int main()
{
    // custom deleter using a state-full lambda
    double data[100]{0};
    auto lmb_sf = [&data](X* ptr){
        // do something
        std::cout<<"In custom deleter using a state-full lambda\n";
        delete ptr;
    };

    std::unique_ptr<X,decltype(lmb_sf)> ptr_sf(new X, lmb_sf);
    std::cout<<"Size of ptr_sf = "<<sizeof(decltype(ptr_sf))<<"\n";

    return 0;
}

按引用捕获输出(即使用 ... lmb_sf = [&data] ...)

Size of ptr_sf = 16
In custom deleter using a state-full lambda

按值捕获输出(即使用 ... lmb_sf = [data] ...)

Size of ptr_sf = 808
In custom deleter using a state-full lambda

【问题讨论】:

  • Lambda 捕获基本上是作为编译器生成的 closeure 类的私有成员创建的。
  • 引用不是魔术。它需要存储空间,在 lambda 内部。
  • @Sepel 引用不是需要存储的。这里的参考没有被优化掉。 (这种优化是可能的,但通常代价高昂。)
  • 其实除了sizeof结果外,unique_ptr实例的大小与内联后生成的代码无关。然而,sizeof 类型的结果(具有外部链接)在大多数实现中受 ABI 要求支配,编译器需要在内部有效地将正在使用的实际类型转换为私有克隆(没有其他观察者行为更改)表示。这项工作需要证明转换的正确性(主要是根据没有额外特定知识的 as-if 规则),这通常很困难且不值得。

标签: c++ lambda c++14 unique-ptr


【解决方案1】:

我了解无状态函子和 lambdas(没有捕获)不会产生大小损失

确实。

那么为什么 lambdas 引用捕获会导致大小损失?

因为捕获 lambda 是有状态的。该状态必须存储在某个地方。

【讨论】:

    【解决方案2】:

    捕获引用的 lambda 必须在内部存储引用。

    虽然我不认为 lambda 对象的大小是由标准规定的,但它在逻辑上必须至少包含捕获的对象的地址。

    【讨论】:

      猜你喜欢
      • 2012-04-11
      • 1970-01-01
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 2016-11-23
      • 1970-01-01
      • 2019-01-16
      • 2015-08-15
      相关资源
      最近更新 更多