46

クラスにいくつかのコンテナーがあります。たとえば、ヒープ上に存在するオブジェクトへの shared_ptr を含むベクターまたはマップです。

例えば

template <typename T>
class MyExample
{
public:

private:
    vector<shared_ptr<T> > vec_;
    map<shared_ptr<T>, int> map_;
};

shared_ptr<const T>このクラスのパブリック インターフェイスを使用して、( を介して) shared_ptrs を const オブジェクトに返すこともあれshared_ptr<T>ば、呼び出し元がオブジェクトを変更できるようにすることもあります。

論理的な const の正確性が必要なので、メソッドを const としてマークすると、ヒープ上のオブジェクトを変更できません。

質問:

1) と の交換可能性に混乱していshared_ptr<const T>ますshared_ptr<T>。誰かがshared_ptr<const T>クラスに a を渡した場合、私は次のことを行いますか?

  • コンテナとして保管するか、shared_ptr<T>それともshared_ptr<const T>コンテナ内に保管しますか?
  • また
  • マップ、ベクター タイプ (insert_element( shared_ptr<const T>obj) など) を変更しますか?

2) 次のようにクラスをインスタンス化する方が良いMyExample<const int>ですか? shared_ptr<int>?を返すことはできないため、これは過度に制限されているように思えます。

4

5 に答える 5

39

shared_ptr<T>交換できshared_ptr<const T>ませ。一方向shared_ptr<T>に変換shared_ptr<const T>できますが、逆方向には変換できません。

観察:

// f.cpp

#include <memory>

int main()
{
    using namespace std;

    shared_ptr<int> pint(new int(4)); // normal shared_ptr
    shared_ptr<const int> pcint = pint; // shared_ptr<const T> from shared_ptr<T>
    shared_ptr<int> pint2 = pcint; // error! comment out to compile
}

経由でコンパイル

cl /EHsc f.cpp

constness に基づいて関数をオーバーロードすることもできます。これら 2 つの事実を組み合わせて、必要なことを行うことができます。

2 番目の質問については、MyExample<int>おそらくよりも理にかなっていMyExample<const int>ます。

于 2010-01-17T03:16:58.490 に答える
13

次の方法論を提案します。

template <typename T>
class MyExample
{
  private:
    vector<shared_ptr<T> > data;

  public:
    shared_ptr<const T> get(int idx) const
    {
      return data[idx];
    }
    shared_ptr<T> get(int idx)
    {
      return data[idx];
    }
    void add(shared_ptr<T> value)
    {
      data.push_back(value);
    }
};

これにより、const の正確性が保証されます。ご覧のように、add() メソッドは <const T> ではなく <T> を使用します。これは、クラスが const T ではなく T を格納することを意図しているためです。ただし、const にアクセスする場合は <const T> を返します。これは、shared_ptr<T> を shared_ptr<const T> に簡単に変換できるため、問題ありません。また、両方の get() メソッドが内部ストレージ内の shared_ptr のコピーを返すため、呼び出し元が誤って内部ポインターが指すオブジェクトを変更することはありません。これはすべて、非スマート ポインターのバリアントに匹敵します。

template <typename T>
class MyExamplePtr
{
  private:
    vector<T *> data;

  public:
    const T *get(int idx) const
    {
      return data[idx];
    }
    T *get(int idx)
    {
      return data[idx];
    }
    void add(T *value)
    {
      data.push_back(value);
    }
};
于 2010-01-17T12:42:17.063 に答える
6

誰かがあなたに合格した場合、shared_ptr<const T>あなたは決して変更できないはずTです。const Tもちろん、を だけにキャストすることは技術的に可能ですが、それは.Tを作成する意図を壊しT constます。したがって、人々がクラスにオブジェクトを追加できるようにしたい場合、彼らはあなたにshared_ptr<T>and noを与える必要がありますshared_ptr<const T>。クラスから変更したくないものを返すとき、つまり を使用するときですshared_ptr<const T>

shared_ptr<T>(明示的なキャストなしで) に自動的に変換できますshared_ptr<const T>が、その逆はできません。メソッドを自由に使用することが役立つ場合があります (とにかくそうする必要があります) const。クラス メソッドを定義するconstと、コンパイラは、データ メンバーを変更したり、const T. したがって、これらのメソッドを使用すると、何かを忘れていないことを確認するのに役立ち、クラスのユーザーがメソッドの意図を理解するのに役立ちます。(例: virtual shared_ptr<const T> myGetSharedPtr(int index) const;)

<const T>2 番目のステートメントは正しいです。クラスを としてインスタンス化することはおそらく望まないでしょうT

于 2010-01-17T02:56:36.020 に答える
3

実現すべきことの 1 つは、次のことです。

tr1::shared_ptr<const T>T const *つまり、それが指すものは constの機能を模倣していますが、ポインター自体はそうではありません。

したがって、共有ポインターに新しい値を割り当てることはできますが、逆参照shared_ptrされたものを左辺値として使用することはできないと思います。

于 2010-01-17T02:27:21.350 に答える