使用 std::optional 还是 std::unique_ptr?

28

我有一个类,其中一个成员是动态分配的(只有在使用时才会分配)。

类似于这样的情况:

class A {};

class B {
    A* aMember;
};

如何更好地替换 A*: std::optional 还是 std::unique_ptr ?

什么时候应使用 std::optional 而不是 std::unique_ptr


B是否拥有指向A的指针?在您的程序中,一个可选的持有nullptr是否有意义? - Jeffrey Bosboom
1
确保 std::optional 将跳过动态分配。这通常会导致更好的性能和更少的内存开销。如果 aMember 只是为了能够为 null 而被动态分配,那么我的选择将是 std::optional - Guillaume Racicot
@JeffreyBosboom 是的,B 负责创建和销毁它。 - Victor Aurélio
@GuillaumeRacicot "动态分配只是为了能够为空" 这是真的。 - Victor Aurélio
@VictorAurélio我建议您使用std::optional。但请注意,与值一样,多态性也不起作用,例如您不能将A的子类保存在可选项中。 - Guillaume Racicot
1个回答

43

std::optional<A> 保证不会进行任何辅助内存分配。这意味着类型为A的潜在对象的原始缓冲区被嵌入到std::optional<A>中。它是std::optional内存占用量的一个组成部分。这意味着std::optional<A>的内存大小将始终至少为sizeof(A),无论该可选的A对象当前是否存在。这就是std::optional<A>B总大小的贡献。

std::unique_ptr<A> 是一个指针。它的大小与常规裸指针的大小大致相同。这就是std::unique_ptr<A>本身在B中占用的内存大小。为了使其指向有效的A对象,您将不得不在其他地方独立分配该A。当存在A时,它占用内存。当不存在A时,它不占用内存。

考虑到上述内容,这是做出决策时要考虑的因素。使用std::optional<A>不涉及动态内存分配/释放,但您所付出的代价可能是在std::optional<A>中存在潜在的“浪费”内存。对于大量实例化和/或大型对象使用std::optional可能会非常浪费,特别是如果该对象在其生命周期中大部分时间处于空状态。

这意味着std::optional的目的并非专门针对可选的长期存储。 std::optional应该被用作本地:例如,可选的局部值、函数的可选参数、可选的返回值。长期使用也可以,只要您不要大量实例化此类对象。

std::unique_ptr<A> 不会浪费内存,但你为此付出的代价是动态内存分配/释放。

当然,所有权语义也非常不同。std::optional 是可复制的。std::unique_ptr 是可移动的,但不可复制。


3
对于考虑懒加载成员(即不能在包含类构造时构造的任何成员)的人来说,一个经验法则是评估该对象在运行时可能存活的比例和大小,如果它是一个可能只有时不时或短暂存活的大对象,那么就继续使用 unique_ptr - underscore_d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接