阅读 RAII 后,查看 Herb Sutter's CppCon2014 presentation ,并阅读 core guidelines和 related articles在过去的几天里,我对所有权和相关语义仍然很困惑。
假设 A 类和 B 类代表物理实体,并且有一个 Scene 类和一个 Process 类。如果您愿意,Process 类是一个main
函数。在现实世界中,A 可以获得 B 并在物理上为自己保留它。它也可以释放它。因此,在 Process 实例的过程中,A 对象必须能够为自己拥有一个 B 实例,并且在完成它之后释放它。 A 和 B 生活在一个场景中,流程必须管理该场景。
B 也是派生的:A 使用一些接口(interface),而 Scene 使用 B 提供的其他接口(interface)。
让我们至少为流程尝试一些代码:
class Process
{
public:
void run();
};
void Process::run()
{
auto scn = Scene {};
auto a = A {};
auto b = B {};
scn.add(a); // stores a
scn.add(b); // stores b
a.acquire(b); // stores b, and represents physical possession of a B
a.doSomething();
a.release(b); // sets a's B instance to null, and physically loses the B
}
如果我错了,请在这里纠正我,这是可疑的部分。
据我了解,A 应该(而不是像代码那样)在堆上并从 shared_ptr 指向,因为进程和场景都有自己的 A 实例。B 也会发生同样的情况,这存储在 a
和 scn
中,正在 中。为什么 scn
不是 make_unique
d?
另一种方法是将所有内容都放在堆栈上(就像在代码片段中一样)。这两种解决方案对我来说似乎是相同的,我根本不理解这两个选项的语义差异,但我倾向于第一个。
最佳答案
C++ 所有权本质上归结为“如果他们在这个特定时刻死亡,谁负责删除这个特定对象”。在您的示例中,由于所有对象都具有自动生命周期,因此所有对象都属于 Process::run
本身。 add
、acquire
或 release
均不涉及所有权转移。
现在,动态生命周期对象的情况如何?您的描述(我假设 C
是指 Scene
)仍然可以通过两种不同的方式实现:
Scene
将std::unique_ptr
保存到A
,这是给定的Scene
和A
可以容纳任一个std::unique_ptr
或std::shared_ptr
s 到B
。
第二个项目符号中的选择可以通过我上面概述的所有权 定义来做出。当 A
拿着 B
死亡时会发生什么?
- 如果
B
也死了,那么A
是它的唯一所有者,应该通过std::unique_ptr
持有它 - 如果
B
应该保留在Scene
中,那么Scene
和A
都是所有者,并且应该两者都通过std::shared_ptr
持有
B
这不包括非拥有(原始)指针,它们可能很有用(例如,如果 A
拥有 B
但 Scene
出于任何目的仍然需要直接引用)。这些必须单独更新。
关于c++ - 有实物表现的所有权,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53444116/