【问题标题】:When to use pointers and when not to?何时使用指针,何时不使用?
【发布时间】:2010-09-28 16:14:09
【问题描述】:

我习惯于进行 Java 编程,在这种情况下,您在编程时不必真正考虑指针。但是,目前我正在用 C++ 编写程序。在创建具有其他类成员的类时,什么时候应该使用指针,什么时候不应该使用?例如,我什么时候想这样做:

class Foo {
    Bar b;
}

与此相反:

class Foo {
    Bar* b;
}

【问题讨论】:

    标签: java c++ pointers


    【解决方案1】:

    从避免指针开始。

    在以下情况下使用它们:

    • 您想使用Pimpl idiomabstract factory
    • Bar 实例实际上由程序的其他部分管理,而 Foo 类只需要能够访问它。
    • 您希望推迟 Bar 对象的构建(即,您希望在构建 Foo 之后创建它)。
    • 在您的业务逻辑中,Bar 对象可能根本不存在;您也可以在 Java 中使用 null。不过,也请查看boost::optional
    • Bar其实是一个基类,需要实例是多态的。
    • 您碰巧使用的工具包更喜欢将 GUI 小部件显示为指针。示例可能包括(但当然不限于)wxWidgetsGLUI

    在任何这些情况 (*) 中,首先使用智能指针,例如 boost::shared_ptr。否则,您迟早可能会忘记释放内存。一旦你知道自己在做什么,请根据具体情况考虑哪种指针类型最好。

    (*) 任何情况——可能除了关于 GUI 小部件的项目符号;在这种情况下,您的工具包很可能也会为您管理资源

    【讨论】:

    • ...或者在您正在编写工具包的情况下(这通常是我的情况)。我从来没有遇到过智能指针可以解决的指针问题,所以我不会说“使用它们!”但“在大多数情况下最容易使用它们。”
    • 也许我一个人。但我认为尤其是初学者应该(当然不是在现实世界的项目中)首先尝试使用原始指针。我认为这类似于问题“IDE/no IDE”。他们应该学会了解为什么智能指针有用以及它们避免了哪些陷阱
    • 在服用和使用它们之前可以神奇地避免其他人告诉他们的一些问题。
    • @litb:我同意你的观点。如果您询问实际项目的最佳实践(这是我正在回答的问题),或者学习理解基本知识,我想答案会有所不同。 OTOH,我想他已经知道如何在基本情况下使用原始指针。
    • 起点应该是 boost::scoped_ptr,只有在需要该功能时才使用 shared_ptr。
    【解决方案2】:
    class Foo {
        Bar b;
    }
    

    b 被 包含 在 Foo 中。如果 Foo 对象结束生命周期, b 也会自动结束生命周期。这就是模型组合。上面的 b 表示对象本身,而不仅仅是像 Java 中那样指向它的指针。因此,如果 b 超出范围,对象将结束生命周期。

    class Foo {
        Bar * b;
    }
    

    这里,b 指向的对象是 使用或 Foo 对象引用。如果 Foo 对象结束生命周期,则 b 指向的对象可能会继续存在,具体取决于情况。这可用于对聚合和一般关系进行建模。例如,该对象可以与其他 Foo 对象共享。

    指针大致就是 Java 中的引用。他们也可以什么都没有。如果指针不指向任何内容,则它是空指针。

    与指针类似的是引用。 C++ 中的引用必须被初始化并且只能指向一个(有效的)对象,该对象的引用被初始化。因此,引用不能保持价值,这可能意味着像 Java 中的 null 这样的“无”。

    【讨论】:

    • 这可能为时已晚,但在第一段中,您不应该说“如果Foo 对象结束生命周期,b 也会自动结束生命周期。”而不是Bar 代替Foo
    • 很好的答案。第一种情况(组合)用于 Bar 依赖于 Foo(汽车的车轮是汽车的一部分),而第二种情况(聚合)用于 Bar 独立于 Foo(驾驶汽车的人)不是汽车的一部分)。
    【解决方案3】:

    在第一个示例中,Bar 对象的内存将在您构造 Foo 对象时自动分配。在第二种情况下,您需要自己分配内存。所以你必须打电话:

    Foo *foo = new Foo();
    foo->b = new Bar();
    

    如果 Bar 对象很大并且您不想将它与 Foo 对象捆绑在一起,这可能是可取的。当 Bar 对象的构造独立于 Foo 对象的创建时也是可取的。在这种情况下, b 对象被“注入”到 foo 中:

    Foo *foo = new Foo();
    foo->b = b_ptr;
    

    b_ptr 是在其他地方构造的,并且一个指针被传递给 foo。

    对于较小的对象,这是很危险的,因为您可能会忘记分配内存。

    【讨论】:

    • new 返回一个指针,而不是一个值。你是说Foo foo吗?或 Foo foo = Foo();代替?
    【解决方案4】:

    在不同的条件下两者都可以。例如,如果在构造 Foo 类的对象时知道如何构造 b,那么第一个就可以了。但如果你不这样做,唯一的选择就是使用第二个。

    【讨论】:

      【解决方案5】:

      你需要做一些汇编编程并很好地理解内存布局。 C 只是一个跨平台程序集,与 Java 或其他语言不同。要正确使用它,应该了解底层细节。

      制作的所有 cmet 都是有效的,但是对于像您这样从高级语言跳到 C 语言的人来说,拥有这种经验将是有益的。有了正确的理解,你就不会再问这样的问题了。

      【讨论】:

      • 请注意,问题是关于 C++,而不是 C。
      • 但是菜鸟不知道 C++ 和 C 的区别。这仍然是一个很好的建议。
      猜你喜欢
      • 2010-11-22
      • 1970-01-01
      • 2019-05-24
      • 2016-03-31
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多