有人可以向 C++ 程序员解释 Java(以及 C#)引用和共享指针(来自 Boost 或来自 C++0x)之间最重要的区别吗?
我或多或少知道shared_ptr是如何实现的。我很好奇以下方面的差异:
1) 性能。 2)骑自行车。 shared_ptr 可以循环(A 和 B 持有指向彼此的指针)。 Java 可以骑自行车吗? 3)还有什么吗?
谢谢你。
性能:
shared_ptr
表现得很好,但根据我的经验,效率比显式内存管理略低,主要是因为它是引用计数的,并且引用计数也必须分配。它的性能如何取决于很多因素,并且它与 Java/C# 垃圾收集器相比的性能只能根据每个用例来确定(取决于语言实现等因素)。
骑自行车只能使用
weak_ptr
,而不是使用两个shared_ptr
。 Java让骑自行车不再费事;它的垃圾收集器将打破循环。我猜 C# 也会做同样的事情。
任何其他:一旦对
shared_ptr
指向的对象的最后一个引用超出范围,它就会被销毁。析构函数被立即调用。在Java中,终结器可能不会立即被调用。我不知道 C# 在这一点上表现如何。
关键区别在于,当共享指针的使用计数变为零时,它指向的对象将立即被销毁(调用析构函数并释放对象)。在 Java 和 C# 中,对象的释放会被推迟,直到垃圾收集器选择释放对象(即,它是不确定的)。
关于周期,我不确定我理解你的意思。在 Java 和 C# 中,两个包含彼此引用的成员字段的对象很常见,从而创建一个循环。例如,汽车和引擎 - 汽车通过引擎字段引用引擎,引擎可以通过汽车字段引用它的汽车。
没有人指出内存管理器在托管内存中移动对象的可能性。因此,在 C# 中,没有简单的引用/指针,它们的工作方式类似于描述管理器返回的对象的 ID。
在 C++ 中,您无法使用 shared_ptr 实现此目的,因为该对象在创建后仍保留在同一位置。
首先,Java/C# 只有指针,没有引用,尽管他们这样称呼它们。引用是 C++ 独有的功能。 Java/C# 中的垃圾收集基本上意味着无限的生命周期。另一方面,当计数变为零时,
shared_ptr
提供共享和确定性破坏。因此,shared_ptr
可以用来自动管理任何资源,而不仅仅是内存分配。从某种意义上说(就像任何 RAII 设计一样),它将指针语义转变为更强大的值语义。
C++ 引用计数指针的循环引用将不会被释放。您可以使用弱指针来解决这个问题。当垃圾收集器愿意时,Java 或 C# 中的循环引用可能会被释放。
当 C++ 引用计数指针中的计数降至零时,将调用析构函数。当 Java 对象不再可访问时,其终结器可能不会立即或永远不会被调用。因此,对于需要显式处置外部资源的对象,需要某种形式的显式调用。
C++
shared_ptr
与 Java 或 C# 中的其他语言之间存在根本区别。
shared_ptr
基于模板该对象不包含
use_count
,但 shared_ptr
包含它。
shared_ptr
。shared_ptr
中,那么我们就有两个 use_count
。如果其中一个变为0,则其他shared_ptr包含一个悬空指针。
weak_ptr
。 (很乱)C++ CLI 语法有一个关键字
ref
来指示一个类被垃圾收集(托管)。
class ref ManagedObj
{
};
weak_ptr
。我的理解是C++可能会走向C#的垃圾收集方式。
[[ ref ]] class ManagedObj
{
};
template <typename T, std::refEmbedded<T>>
class shared_ptr { /* old impl */ int use_count; };
template <typename T, true>
class shared_ptr { /* new impl */ };