构造函数依赖注入:unique_ptr + move vs shared_ptr
Constructor dependency injection: unique_ptr + move vs shared_ptr
假设我们有这样的东西:
struct Complex{
Complex(Part1 p1, Part2 p2, Part3 p3)
}
Part1 p1;
Part2 p2;
Part3 p3;
但是传递副本是无效的,所以我们需要转向指针。问题是使用什么类型 — unique_ptr
或 shared_ptr
乍一看,由于Complex
是p1, p2, p3
的真正所有者,所以unique_ptr
似乎更好;但是,由于无法复制,我们需要使用 std::move
.
所以我的问题是——对于这种情况,什么是更好的方法,从 Part
中创建 unique_ptr
,然后在 Complex
的构造函数中使用 move
, 或者从头开始创建 shared_ptr
并改用 shared_ptr
?
最好的解决方案是让 Part
类型的移动成本更低,然后将它们移入。但是,如果这不是一个选项,您将不得不求助于动态管理它们。
正如您所说,Complex
拥有这些部分,因此它应该接受它们作为 std::uniqe_ptr<Part>
并将这些指针移动到它自己中。移动 std::unique_ptr
非常便宜:它可能只涉及两个指针分配。
另一方面,使用 std::shared_ptr
和复制涉及不必要的 atomic 递增(用于创建副本)和递减(用于破坏原件)。对于当今的缓存密集型多核处理器来说,原子操作当然远非便宜。
因此,只要坚持代码的预期语义(唯一所有权,用 std::unique_ptr
惯用地表达),您将获得良好的性能作为奖励。
假设我们有这样的东西:
struct Complex{
Complex(Part1 p1, Part2 p2, Part3 p3)
}
Part1 p1;
Part2 p2;
Part3 p3;
但是传递副本是无效的,所以我们需要转向指针。问题是使用什么类型 — unique_ptr
或 shared_ptr
乍一看,由于Complex
是p1, p2, p3
的真正所有者,所以unique_ptr
似乎更好;但是,由于无法复制,我们需要使用 std::move
.
所以我的问题是——对于这种情况,什么是更好的方法,从 Part
中创建 unique_ptr
,然后在 Complex
的构造函数中使用 move
, 或者从头开始创建 shared_ptr
并改用 shared_ptr
?
最好的解决方案是让 Part
类型的移动成本更低,然后将它们移入。但是,如果这不是一个选项,您将不得不求助于动态管理它们。
正如您所说,Complex
拥有这些部分,因此它应该接受它们作为 std::uniqe_ptr<Part>
并将这些指针移动到它自己中。移动 std::unique_ptr
非常便宜:它可能只涉及两个指针分配。
另一方面,使用 std::shared_ptr
和复制涉及不必要的 atomic 递增(用于创建副本)和递减(用于破坏原件)。对于当今的缓存密集型多核处理器来说,原子操作当然远非便宜。
因此,只要坚持代码的预期语义(唯一所有权,用 std::unique_ptr
惯用地表达),您将获得良好的性能作为奖励。