12

C++ では、パフォーマンスとデータの整合性の観点から、コレクションを公開するためにどのような代替手段がありますか?

私の問題は、データの内部リストを呼び出し元に返したいのですが、コピーを生成したくないということです。Thant は、リストへの参照を返すか、リストへのポインターを返すかのいずれかを残します。ただし、呼び出し元にデータを変更させることに夢中になっているわけではなく、データを読み取らせたいだけです。

  • パフォーマンスとデータの整合性のどちらかを選択する必要がありますか?
  • もしそうなら、一般的には一方通行の方が良いですか、それともケースに特有のものですか?
  • 他の選択肢はありますか?
4

10 に答える 10

7

多くの場合、呼び出し元はコレクションを反復処理するためだけにアクセスしたいと考えています。Rubyの本からページを取り出して、反復をクラスのプライベートな側面にします。

#include <algorithm>
#include <boost/function.hpp>

class Blah
{
  public:
     void for_each_data(const std::function<void(const mydata&)>& f) const
     {
         std::for_each(myPreciousData.begin(), myPreciousData.end(), f);
     }

  private:
     typedef std::vector<mydata> mydata_collection;
     mydata_collection  myPreciousData;
};

このアプローチでは、内部について何も公開していません。つまり、コレクションさえあります。

于 2008-09-05T01:08:17.283 に答える
5

配列、ベクトルなどを使用している場合、RichQの答えは合理的な手法です。

序数値で索引付けされていないコレクションを使用している場合...または近い将来に必要になる可能性があると思われる場合は、独自のイテレータ型を公開することを検討してください。関連するbegin()/end()メソッド:

class Blah
{
public:
   typedef std::vector<mydata> mydata_collection;
   typedef myDataCollection::const_iterator mydata_const_iterator;

   // ...

   mydata_const_iterator data_begin() const 
      { return myPreciousData.begin(); }
   mydata_const_iterator data_end() const 
      { return myPreciousData.end(); }

private:
   mydata_collection  myPreciousData;
};

...通常の方法で使用できます。

Blah blah;
for (Blah::mydata_const_iterator itr = blah.data_begin();
   itr != blah.data_end();
   ++itr)
{
   // ...
}
于 2008-09-04T20:56:04.113 に答える
3

たぶん、このようなものですか?

const std::vector<mydata>& getData()
{
  return _myPrivateData;
}

ここでの利点は、非常にシンプルで、C++ と同じくらい安全であることです。RobQが示唆するように、これをキャストできますが、コピーしていない場合、誰かがそれを妨げるようにすることはできません. ここでは、 を使用する必要がありますconst_cast。これは、探している場合に簡単に見つけることができます。

代わりに、イテレータを使用してもほとんど同じ結果が得られる可能性がありますが、より複雑です。ここで反復子を使用することの唯一の追加の利点 (私が考えることができる) は、カプセル化を改善できることです。

于 2008-09-04T20:24:52.597 に答える
2

const 参照または共有ポインターの使用は、基になるコレクションの内容が時間の経過とともに変化しない場合にのみ役立ちます。

あなたのデザインを検討してください。呼び出し元は本当に内部配列を見る必要がありますか? 呼び出し元がオブジェクトに配列の処理方法を指示するようにコードを再構築できますか? たとえば、呼び出し元が配列を検索する場合、所有者オブジェクトはそれを実行できますか?

結果ベクトルへの参照を関数に渡すことができます。一部のコンパイラでは、コードがわずかに高速になる場合があります。

最初に再設計を試み、2 番目にクリーンなソリューションを使用し、3 番目に (必要に応じて) パフォーマンスを最適化することをお勧めします。

于 2008-09-04T21:09:32.490 に答える
2

@ Shog9 と @RichQ の両方のソリューションの利点の 1 つは、コレクションの実装からクライアントを切り離すことです。

コレクションの種類を別のものに変更しても、クライアントは引き続き機能します。

于 2008-09-04T21:12:37.333 に答える
1

必要なのは、データのブロブ全体をコピーせずに読み取り専用アクセスを行うことです。いくつかのオプションがあります。

まず、上記のように、データ コンテナーが何であれ const 参照を返すことができます。

const std::vector<T>& getData() { return mData; }

これには具体性という欠点があります。クラスのインターフェースを変更せずにデータを内部に保存する方法を変更することはできません。

次に、実際のデータへの const 化されたポインターを返すことができます。

const T* getDataAt(size_t index)
{
   return &mData[index];
}

これは少し優れていますが、getNumItems 呼び出しを提供し、範囲外のインデックスから保護する必要もあります。また、ポインターの const-ness は簡単にキャストされ、データは読み書き可能になりました。

もう 1 つのオプションは、イテレータのペアを提供することですが、これはもう少し複雑です。これにはポインターと同じ利点があり、(必ずしも) getNumItems 呼び出しを提供する必要がなく、イテレーターから const-ness を取り除くためにかなり多くの作業が必要になります。

おそらくこれを管理する最も簡単な方法は、Boost Range を使用することです。

typedef vector<T>::const_iterator range_iterator_type;
boost::iterator_range< range_iterator_type >& getDataRange()
{
    return boost::iterator_range(mData.begin(), mData.end());
}

これには、ウェブサイトでわかるように、範囲が構成可能、フィルター可能などであるという利点があります。

于 2008-09-04T21:12:36.553 に答える
0

次の2つの記事では、コンテナクラスのカプセル化に関連する問題のいくつかとその必要性について詳しく説明しています。それらは完全に機能するソリューションを提供しませんが、本質的にはShog9によって与えられたのと同じアプローチにつながります。

パート1:カプセル化と吸血鬼
パート2(これを読むには無料登録が必要になりました): ケブリン・ヘニーによる列車の難破スポッティング

于 2009-06-08T10:03:05.567 に答える
0

EnumChildWindowsの行に沿ってコールバックを使用することをお勧めします。ユーザーがデータを変更できないようにするための手段を見つける必要があります。多分constポインタ/参照を使用してください。

一方、各要素のコピーをコールバック関数に渡して、毎回コピーを上書きすることができます。(コレクション全体のコピーを生成する必要はありません。一度に1つの要素だけコピーを作成することをお勧めします。これには、多くの時間/メモリは必要ありません)。

MyClass tmp;
for(int i = 0; i < n; i++){
    tmp = elements[i];
    callback(tmp);
}
于 2009-06-09T05:43:21.827 に答える
0

std::list単純な古いデータ (.NET が「値の型」と呼ぶもの) がある場合、そのリストへの const 参照を返すことは問題ありません (のような邪悪なものは無視します) const_cast

std::listポインター (または)がある場合、それはコレクション内のアイテムboost::shared_ptrはなく、コレクションの変更のみを停止します。私の C++ はさびすぎて、現時点でその答えを伝えることができません :-(

于 2008-09-04T21:08:10.747 に答える
0

const の使用は妥当な選択です。また、共有ポインターの実装については、boost C++ ライブラリを確認することもできます。これはポインタの利点を提供します。つまり、参照では許可されない共有ポインタを「null」に戻す必要がある場合があります。

http://www.boost.org/doc/libs/1_36_0/libs/smart_ptr/smart_ptr.htm

あなたの場合、共有ポインタの型を const にして書き込みを禁止します。

于 2008-09-04T20:32:07.587 に答える