- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在查看 std::function
的 GCC 实现(在调试时到达那里并在切线上离开)。
从我所看到的,它在本地存储中存储了小类型,任何不适合它的东西都通过 new 操作符分配。
然而,构造函数也会检查 __location_invariant
元函数,它是 std::trivially_copyable
的包装器trait,如果它不是“位置不变”,它也会在堆上分配它。
我不完全理解它为什么这样做,正如我所理解的::new (storage) T(args)
应该提供相同的结果new T(args)
除了就地构造函数不分配任何内存。
例如,如果它使用单个引用计数对象来存储太大而无法放入本地存储的“位置不变”类型,那对我来说会更有意义,因为这会减少分配和复制的数量。由于每次都分配和复制非不可变对象(immutable对象),因为它们是“位置相关的”,它们不能都引用相同的存储。
实现似乎只是堆分配任何不适合和/或不是位置不变的东西(至少我没有看到它这样做?),所以我很困惑为什么它需要检查位置不变性,如果功能上没有明显区别。
最佳答案
似乎 libstdc++ 使用“位置不变”属性来简化 std::function
上的某些操作。 .即,可调用对象的存储由 union named _Any_data
提供。其中包含一个字符数组。这个 char 数组可以为指向实际可调用对象的指针(如果它在堆上分配)或可调用对象本身(如果它有资格进行小对象优化)提供存储。当std::function
是移动构造的,_Any_data
RHS 的成员只需简单地复制到 _Any_data
*this
成员(member)(加上 RHS 必须以某种方式表示为空)。这在 _Any_data
时都有效存储一个指向堆分配的可调用对象的指针(因为该指针是可简单复制的),并且当它存储一个小的内联可调用对象时(因为在这种情况下需要可调用对象是可简单复制的)。类似的交换操作 std::function
可以作为 _Any_data
的简单交换来实现成员和复制/移动赋值操作都是使用复制交换习语实现的。
可能会更慷慨一些:理论上可以支持任何可调用类型,无论是 nothrow-copy-constructible 还是 nothrow-move-constructible,都可以支持小对象优化。 [1] 然而,在类型不可简单复制的情况下,这会给实现带来额外的复杂性。考虑如何写std::function
的移动构造函数以防 RHS 可能会内联存储一个不能简单复制的对象。在这种情况下,必须根据存储的元数据是否表明此类构造函数是非平凡的,有条件地调用此类可调用对象的复制构造函数。这并不难实现:只需将一个额外的方法添加到管理器对象中即可。但是,这意味着每次 std::function
都必须执行额外的间接函数调用。是移动构造的。在交换操作的情况下,需要 3 次这样的调用。
实现者需要做出的权衡是,适合小对象缓冲区且不可抛出移动(但不能简单复制)的类型是否足够普遍,以至于允许它们存储在小对象缓冲区中的好处超过所有可调用类型的移动和交换操作使用的额外间接函数调用的成本。
[1] 这个要求是必要的原因(或至少一个原因)是交换两个 std::function
对象必须始终成功。交换操作实际上必须重新定位任何内联存储的值(与堆上的值相反,在这种情况下,指针的所有权可能会简单地转移到另一个 std::function
对象)。如果此类重定位中涉及的底层复制或移动不是 noexcept
,则无法保证交换会成功;因此堆分配是唯一的选择。
关于c++ - 为什么位置不变性对 std::function 很重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69845195/
我是一名优秀的程序员,十分优秀!