在C++中,一个返回指向非const对象的指针的const方法被认为是不好的实践吗?

10

在C++中,一个返回非const对象指针的const方法是否被视为不良实践?例如,考虑以下方法:

// Makes perfect sense
bool isActive() const { return m_isActive; }

// Makes perfect sense, both consts ensure nothing is modified
const SomeObject* someObject() const { return m_someObject; }

// Makes perfect sense, no const because SomeObject is mutable,
// thus MyClass is indirectly mutable
SomeObject* someObject() { return m_someObject; }

// Makes no sense, if you're just returning a pointer to a const object,
// then the method should clearly be const since nothing can be modified
const SomeObject* someObject() { return m_someObject; }

最后一个组合让我感到困惑:以下代码是否被认为是不良实践?

SomeObject* someObject() const { return m_someObject; }

因为方法返回的类不是const,但是方法本身是const,所以它有点毫无意义,因为你可以修改SomeObject并因此间接修改你的类...那么这种形式是否被认为是不好的做法?例如,你应该只使用以下一种来代替它吗?

const SomeObject* someObject() const { return m_someObject; }
SomeObject* someObject() { return m_someObject; }

实际情况:我正在编写一个智能手机游戏,其中包含一个名为Game的类。Game类包含几个方法,这些方法返回指向实用程序类(例如InputManagerAudioManager等)的指针。

class Game
{
public:
    InputManager* inputManager() const { return m_inputManager; }
    ...

private:
    InputManager* m_inputManager;
    ...
}

inputManager()成为const,这样做有任何意义吗?因为它返回的对象不是const,也不应该是const(因为InputManager需要可变以便更新其状态等等)。

还是应该删除方法中的const修饰符,以更准确地反映方法的行为?这样,如果我有一个const Game,我就不能调用inputManager(),并混淆Game的输入管理器,即使Gameconst

5个回答

5
这取决于非const指针是否指向const对象内部的某些内容,还是新分配的可变内存。如果返回的是字符串副本,则其非const是可以接受的,即使原始字符串是const。副本的所有权已从方法传递到调用代码;确保适当地销毁副本现在是调用代码的问题(可能是一个非常小的问题)。但是,从const对象内部返回非const指针是一个非常糟糕的主意。

1
如果对象A“拥有”对象B,并且您希望将A视为const,则对B的访问器也应为const。如果A不拥有B,则一切都无法确定。正如OP所指出的,在C ++中,这是一个风格问题。更加追求严谨的语言会强制执行此操作。 - Bob Murphy

2

这是完全可以接受的。const方法意味着您不会修改调用其方法的对象 - 它并不涉及其他任何对象。当然,该对象可能是“this”的一部分,或者它本身就是“this” - 但这已经超出了重点。

总的来说,“const”更像是一个承诺而不是其他什么,但其基本思想是相同的 - const方法表示“this”是const,除此之外没有其他。


1
其实,不是this是常量,而是我不会使用这个特定的方法修改this。我想这就是你在第一段中所说的,但似乎有点不清楚。Const通常是一个承诺,不通过标记为const的特定手段来更改某些东西。对于指向const、引用const等情况,所引用的对象往往通过其他引用是非const的,并通过该引用进行修改。成员数据中的const引用经常是一个例子——承诺类不会修改它所引用的对象,但没有更多的保证。 - user180247

0
在我看来,无论是否为const,返回成员指针都是一个不好的主意。
当一个对象返回其私有成员的句柄时,其他人可以通过此句柄更改私有成员。对象的状态可能会不一致,并引起许多麻烦。即使有const,调用者仍然可以使用const cast绕过此检查。因此,返回任何对象的私有成员的句柄都不是一个好主意。

1
如果你的类的用户使用const_cast来规避你所设定的保护措施,那么他们就应该承担任何麻烦。 - Dennis Zickefoose
@Dennis 我完全同意。另外,当人们认为像C#和Java这样的语言没有const是一件好事时,我给出的另一个回应是“反射”。只需要一个词。 :) - Jake Petroules

0
在您的情况下,GameInputManager 对象似乎是单例。如果是这种情况,您只需要确保只存在一个 Game 实例(仅包含一个 InputManager),并跳过 const 修饰符。如上所建议,在这种情况下,我会返回对包含对象的引用,而不是指针。

0

我认为在这里 const 并不重要。

通常不建议返回属性的句柄(指针、引用):

  • 它将用户绑定到特定的实现,使得无法更改
  • 它使得无法强制执行不变量(非 const 版本),你现在可能没有这样的需求,但未来你永远不知道会发生什么

如果您开始直接访问属性,则它们与 public 一样好。

示例:

class Foo
{
public:
  std::vector<Bar> const& bars() const; // Ooops, impossible to move to a `deque`
                                        // or to enable polymorphic behavior
private:
  std::vector<Bar> mBars;
};

最好返回值,这样如果你更改内部结构,就可以始终提供新方法并在旧方法中进行一些转换,以避免破坏接口(将其标记为已弃用等)。
记住:因为暴露私处而被送进监狱的人可不少!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接