有人可以向C ++程序员解释Java(和C#)引用和shared_ptr(来自Boost或来自C ++ 0x)之间最重要的区别。
我或多或少知道如何实现shared_ptr。我很好奇以下几个方面的差异:
1)表现。 2)骑自行车。 shared_ptr可以循环(A和B保持彼此的指针)。在Java中可以骑自行车吗? 3)还有别的吗?
谢谢。
答案 0 :(得分:4)
性能:shared_ptr
表现相当不错,但根据我的经验,效率略低于显式内存管理,主要是因为它是引用计数而且引用计数也必须分配。它的执行情况取决于很多因素,它与Java / C#垃圾收集器的比较只能根据每个用例来确定(取决于其他因素中的语言实现)。
循环仅适用于weak_ptr
,而不能使用两个shared_ptr
。 Java允许骑自行车而不用再费力;它的垃圾收集器将break the cycles。我的猜测是C#也是这样。
其他任何东西:shared_ptr
指向的对象在最后一次引用超出范围时就会被销毁。析构函数立即被调用。在Java中,可能不会立即调用终结器。我不知道C#在这一点上的表现如何。
答案 1 :(得分:3)
关键的区别在于,当共享指针的使用计数变为零时,它指向的对象将被立即销毁(析构函数被调用并且对象被释放)。在Java和C#中,对象的解除分配被推迟,直到垃圾收集器选择解除分配对象(即,它是非确定性的)。
关于周期,我不确定我明白你的意思。在Java和C#中,有两个对象包含相互引用的成员字段,从而创建一个循环。例如汽车和发动机 - 汽车通过发动机领域引用发动机,发动机可以通过汽车领域参考其汽车。
答案 2 :(得分:1)
不会处理带有C ++引用计数指针的循环引用。你可以使用弱指针来解决这个问题。当垃圾收集器感觉像它时,可以处理Java或C#中的循环引用。
当C ++引用计数指针中的计数降为零时,将调用析构函数。当Java对象不再可访问时,可能无法立即或永远调用其终结器。因此,对于需要显式处理外部资源的对象,需要某种形式的显式调用。
答案 3 :(得分:1)
首先,Java / C#只有指针,而不是引用,尽管他们这样称呼它们。 Reference是一种独特的C ++功能。 Java / C#中的垃圾收集基本上意味着无限的生命周期。另一方面,当计数变为零时,shared_ptr
提供共享和确定性破坏。因此,shared_ptr
可用于自动管理任何资源,而不仅仅是内存分配。从某种意义上说(就像任何RAII设计一样)它将指针语义转换为更强大的价值语义。
答案 4 :(得分:1)
没有人指出内存管理器在托管内存中移动对象的可能性。所以在C#中没有简单的引用/指针,它们就像描述管理器返回的对象的ID一样 在C ++中,您无法使用shared_ptr实现此目的,因为对象在创建后仍保留在同一位置。