【问题标题】:C++: Any reason why function returning pointer shouldn't be const?C++:函数返回指针不应该是 const 的任何原因?
【发布时间】:2011-07-19 09:22:46
【问题描述】:

我想知道返回指针的函数是否有任何理由不应该是 const。我正在处理一些在大多数地方似乎都是 const 正确的代码,但由于某种原因,它没有将返回指针的函数声明为 const。例如,它写

virtual Joint* getJointByID(unsigned int id);

而不是

virtual Joint* getJointByID(unsigned int id) const;

如果 getJointByID 函数本身实际上并没有改变类的任何成员,那么有什么理由不应该存在 const 吗?

【问题讨论】:

  • 可以通过指针改变对象的状态吗?
  • 通过返回的指针,是的,但是函数调用本身永远不会改变任何类的数据成员。

标签: c++


【解决方案1】:

这实际上是有道理的。如果要使用const 声明函数,则意味着它可以用于常量实例(constvar.getJointByID...)。但是如果它返回一个指向可以修改的内部结构的指针,它将允许用户绕过实例的 const 限制。

当不使用const 声明时(就像它一样),您不能在 const 实例上调用该函数,因此保留了 const 性。如果它被声明为const,它最好返回一个const Joint*。

(我在这里假设 Joint* 确实是类数据结构的一部分。如果类返回一些 Joint 左右的新分配的副本,它可以不保持不变。这取决于实现)

【讨论】:

  • + 1. 很好地解释了代码设计成这种方式的原因。是的,Joint 是类数据的一部分,通过引用传递。
【解决方案2】:

常量的正确性不仅仅取决于返回类型;您从该方法返回的内容也很重要。

如果您要返回对象内部的一些数据,则方法上的const 修饰符将不允许其他人能够修改此内部数据。即使您不修改方法内部的对象,您也不能简单地将内部提供给外部世界并获得突变许可。当您在类的常量实例化上调用此方法时,这没有任何意义。

最好的办法是通过使用指向常量的指针来保护成员数据来返回它:

virtual const Joint* getJointByID(unsigned int id) const;

【讨论】:

  • 我希望有可能通过返回的指针改变对象的状态。那么......这是否意味着我不应该将函数声明为 const?另外,如果我确实返回了一个 const Joint*,它不能作为左值取消引用,但仍然可以作为右值取消引用?还是 const 仅适用于指针值而不适用于指针指向的内容?
  • @Gravity - 常量方法是可以从常量对象调用的方法。如果你想改变一个对象的内部状态,那么它就不能是一个常量对象,所以你不能将你的方法声明为常量。 const Joint* 表示指向常量 Joint 对象的指针。它指的是对象而不是指针。但在任何一种情况下,您都不能将返回值用作左值。作为返回类型的原始类型(在这种情况下为指针)在语言设计中是不可变的。这是与您的问题无关的特殊情况。
  • 我的意思是取消引用这样一个指针的结果,而不是指针类型本身。也就是说,我真的可以做 (*returnedJoint) = something;仅当 returnedJoint 未使用 const 标记时?
  • @Gravity - 如果它不是指向 const 的指针,是的,你可以这样做。这就是为什么不允许您从 const 方法返回它的原因。您可以抛弃常量,但只有在对象未标记为常量时才能通过指针修改对象,除非您当然不通过指针技巧覆盖对象的内存区域。编译器假定你不会做那样的事情。
【解决方案3】:

返回值的类型与 const-correction 没有关系。

但是如果您返回的指针位于对象的一部分结构中,那么您应该返回指向const 的指针,或者不要将该函数声明为const,因为您是能够通过该指针更改对象。

【讨论】:

    【解决方案4】:

    我想知道函数是否有任何理由返回 指针不应该是 const。

    没有这样的经验法则。 constness 取决于你在函数内部做什么。

    如果 getJointByID 函数本身实际上并没有改变任何成员 类的,有什么理由不应该有 const 吗?

    你说得对。作为良好编程实践的一部分,该函数应该是const。但是,这不是强制性的。

    此外,大多数情况下,派生类在打算覆盖其virtual 方法时遵循与基类相同的方法模式。现在,如果基类是遗留的,则不能通过输入const 来更改其语法;所以所有派生类都遵循相同的链。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-07
      • 1970-01-01
      • 2020-06-17
      相关资源
      最近更新 更多