使用什么 std::optional 或 std::unique_ptr
What to use std::optional or std::unique_ptr
我有一个 class 有一个成员是动态分配的(它只在使用时分配)。
这样想:
class A {};
class B {
A* aMember;
};
用什么替换 A*
会更好:std::optional
或 std::unique_ptr
?
以及何时使用 std::optional
而不是 std::unique_ptr
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>
不涉及动态内存 allocation/deallocation,但您为此付出的代价可能是 std::optional<A>
中的 "wasted" 内存。对大量实例化的 and/or 大型对象使用 std::optional
可能会被证明是非常浪费的,尤其是当对象的大部分生命周期都处于空状态时。
这意味着std::optional
的目的并不完全是针对可选的长期存储。 std::optional
是要在 本地 使用的东西:例如作为可选的本地值,函数的可选参数,可选的 return 值。长期使用也是可以的,只要你不是大量实例化这类对象即可。
std::unique_ptr<A>
不会浪费内存,但你为此付出的代价是动态内存allocation/deallocation.
当然,所有权语义也大不相同。 std::optional
可复制。 std::unique_ptr
可移动,但不可复制。
我有一个 class 有一个成员是动态分配的(它只在使用时分配)。
这样想:
class A {};
class B {
A* aMember;
};
用什么替换 A*
会更好:std::optional
或 std::unique_ptr
?
以及何时使用 std::optional
而不是 std::unique_ptr
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>
不涉及动态内存 allocation/deallocation,但您为此付出的代价可能是 std::optional<A>
中的 "wasted" 内存。对大量实例化的 and/or 大型对象使用 std::optional
可能会被证明是非常浪费的,尤其是当对象的大部分生命周期都处于空状态时。
这意味着std::optional
的目的并不完全是针对可选的长期存储。 std::optional
是要在 本地 使用的东西:例如作为可选的本地值,函数的可选参数,可选的 return 值。长期使用也是可以的,只要你不是大量实例化这类对象即可。
std::unique_ptr<A>
不会浪费内存,但你为此付出的代价是动态内存allocation/deallocation.
当然,所有权语义也大不相同。 std::optional
可复制。 std::unique_ptr
可移动,但不可复制。