【问题标题】:Comparing shared_ptr to managed language references将 shared_ptr 与托管语言参考进行比较
【发布时间】:2011-06-02 00:47:31
【问题描述】:

谁能向 C++ 程序员解释 Java(以及 C#)引用和 shared_ptr(来自 Boost 或来自 C++0x)之间的最重要区别。

我或多或少知道 shared_ptr 是如何实现的。我很好奇以下方面的差异:

1) 性能。 2) 骑自行车。 shared_ptr 可以循环(A 和 B 相互保存指针)。在 Java 中可以循环吗? 3) 还有什么?

谢谢。

【问题讨论】:

    标签: c# java c++


    【解决方案1】:

    没有人指出内存管理器在托管内存中移动对象的可能性。所以在 C# 中没有简单的引用/指针,它们的工作方式类似于描述由管理器返回的对象的 ID。
    在 C++ 中,您无法使用 shared_ptr 来实现此目的,因为对象在创建后仍保留在同一位置。

    【讨论】:

      【解决方案2】:

      不会释放带有 C++ 引用计数指针的循环引用。您可以使用弱指针来解决此问题。 Java 或 C# 中的循环引用可能会在垃圾收集器喜欢时被释放。

      当 C++ 引用计数指针中的计数降至零时,将调用析构函数。当一个 Java 对象不再可访问时,它的终结器可能不会立即或永远不会被调用。因此,对于需要显式处理外部资源的对象,需要某种形式的显式调用。

      【讨论】:

        【解决方案3】:

        首先,Java/C# 只有指针,没有引用,尽管它们是这样称呼的。引用是一个独特的 C++ 特性。 Java/C# 中的垃圾收集基本上意味着无限的生命周期。另一方面,shared_ptr 在计数变为零时提供共享和确定性销毁。因此,shared_ptr 可用于自动管理任何资源,而不仅仅是内存分配。在某种意义上(就像任何 RAII 设计一样),它将指针语义转化为更强大的值语义。

        【讨论】:

        • “指针”和“引用”之间的 C++ 区别是该语言特有的。 C#/Java 引用介于两者之间,因为您不能对它们进行指针运算。
        • @larsmans,问题是 Java 从语义上讲,不仅有指针,而且只有指针。它缺少保证引用永远不会为空的引用机制。但它确实没有指针运算,表面的句法符号也不是通常的指针符号。
        • 但是您所说的具有误导性,因为它假定 C++ 定义了“引用”是什么。 Java 有引用,因为它们被称为引用。它们只是不像 C++ 引用。
        • 问题是两种不同的语言对同一个词有不同的含义。它的含义特定于语言的上下文(不幸的是,初级开发人员不明白这一点,并认为当他们切换语言时,同一个词意味着同样的事情)。我认为 Gene 走在正确的轨道上,他只需要稍微改一下答案。看看 local 在不同语言中的含义(C/C++/Java/C# 中的局部变量与 perl 的切换相对相似,而 local 在这种情况下具有全新的含义)。
        【解决方案4】:

        主要区别在于,当共享指针的使用计数变为零时,它指向的对象立即被销毁(调用析构函数并释放对象)。在 Java 和 C# 中,对象的释放被推迟,直到垃圾收集器选择释放对象(即,它是不确定的)。

        关于周期,我不确定我理解你的意思。在 Java 和 C# 中,拥有两个包含相互引用的成员字段的对象是很常见的,从而创建了一个循环。例如汽车和引擎 - 汽车通过引擎字段引用引擎,引擎可以通过汽车字段引用其汽车。

        【讨论】:

        • 在 C# 和 Java 中没有“正常”的析构函数,它们只有终结器,这在这些语言中被认为是错误的。析构函数和垃圾收集是不一致的。 GC 基本上意味着:没有破坏,或者无限的对象生命周期。
        • 析构函数的概念(如在函数中被调用)和对象的销毁(如其释放)之间存在差异。我知道这经常会让人感到困惑,因为这两个事件都使用相同的术语,所以也许对象释放会是一个更好的选择词来引用后面的事件。
        • 破坏不是解除分配,它们是非常不同的概念,不应该互换使用。
        【解决方案5】:

        性能shared_ptr 性能相当不错,但根据我的经验,它的效率略低于显式内存管理,主要是因为它是引用计数的,而且引用计数也必须分配。它的性能有多好取决于很多因素,它与 Java/C# 垃圾收集器相比的好坏只能根据每个用例来确定(取决于其他因素中的语言实现)。

        骑自行车只能使用weak_ptr,不能使用两个shared_ptrs。 Java 允许毫不费力地骑自行车;它的垃圾收集器将break the cycles。我的猜测是 C# 也是如此。

        其他任何东西shared_ptr 指向的对象在最后一次引用超出范围后立即被销毁。立即调用析构函数。在 Java 中,可能不会立即调用终结器。我不知道 C# 在这一点上的表现如何。

        【讨论】:

        • 注意性能,如果使用make_shared (boost.org/doc/libs/release/libs/smart_ptr/make_shared.html),那么引用计数和被引用对象都分配在一个块中。
        • 可以说,shared_ptr 对性能的最大影响是引用计数器的联锁递增/递减
        • @sbk:你为什么认为这会影响性能。它通常被实现为单个汇编指令(无需锁定支持它的硬件)。
        • @LokiAstari 在我使用的应用程序中(shared_ptrs 很重),联锁 inc/dec 占总时间的 14%。
        • @larsmans :在 C# 中,对象也不会立即销毁。但是您可以使用using 强制执行此操作。
        猜你喜欢
        • 2011-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多