0

ポインターの配列を持つクラスがあり、ポインターを逆参照して参照として返すメソッドがあるとします。メソッドの呼び出し元が、ポインターが指しているオブジェクトの非 const メソッドを呼び出せるようにしたいだけでなく、ポインターが指しているオブジェクトを変更する呼び出し元から自分自身を保護したいと考えています。const 参照を返す場合、ポインター オブジェクトのメソッドの多くを const としてマークする必要があるため、そのクラス メンバー変数の多くを可変としてマークする必要があります。

  1. これは悪い習慣ですか?もしそうなら、どうすればこれを回避できますか?
  2. ミュータブルを使いすぎるとパフォーマンスが低下しますか?

例:

#include <iostream>
#include <array>
#include <memory>

class Counter
{
public:
  Counter();
  void hit() const;
  void reset();
  unsigned count() const;
private:
  mutable unsigned count_;
};

Counter::Counter() : count_(0) {}

void Counter::hit() const { ++count_; }

void Counter::reset() { count_ = 0; } 

unsigned Counter::count() const { return count_; }

class CircularArray
{
public:
  CircularArray();
  const Counter& next() const;
private:
  mutable unsigned i_;
  std::array<std::unique_ptr<Counter>, 3> arr_;
};

CircularArray::CircularArray() : i_(2)
{
  arr_[0] = std::unique_ptr<Counter>(new Counter);
  arr_[1] = std::unique_ptr<Counter>(new Counter);
  arr_[2] = std::unique_ptr<Counter>(new Counter);
}

const Counter& CircularArray::next() const { return *arr_[(i_ = (i_ + 1) % 3)]; }

int main()
{
  CircularArray circular;
  const Counter* p;
  p = &circular.next();

  p->hit();
  p->hit();

  Counter c;
  //*p = c; // <-- Want to prevent this
}
4

1 に答える 1

1

私が言ったことを拡張するmutableために、これを悪用しても意味がありません。これだけを防止したい場合:

*p = /* ... */;

の代入演算子を削除することで、はるかに簡単に実行できますCounter

class Counter
{
    void operator=(const Counter&) = delete;
    // ...
};

代入演算子はオブジェクトのアイデンティティーに影響を与えないことに注意してください: アドレスを変更しません。this意味的には、オブジェクトを変更して別のオブジェクトの状態を複製する割り当て。実際、代入演算子の使用を禁止されたとしても、次のようにすることができます。

// a very inefficient way of performing `*p = c`
p->reset();
while (p->count() != c.count())
    p->hit();

これは、非常に不器用で非効率的ではありますが、割り当てを実行するのとまったく同じ結果を達成します。

代入を実行することは、 type の単一の引数を受け入れる非 const メンバー関数を呼び出すことと同じですconst Counter&。仮説的には、代入演算子を再定義して、必要に応じてまったく何もしないようにすることもできます (ただし、それは悪い考えです)。

于 2014-12-04T06:25:16.713 に答える