3

私は答えを探すのにしばらく時間を費やしましたが、満足のいくものは何も見つかりませんでした。

私はプロトタイピングよりも少し多くのプロダクション関連のコーディングを行っているので、経験豊富なC++の人々がこの種の問題をどのように解決するかに興味があります。

大量のデータ、たとえば500Mbを保持するunordered_map(ハッシュマップ)を言うクラスがあるとします。そのデータのサブセットを効率的に返すアクセサーを作成する必要があります。

次のようになります。ここで、BigDataは、適度な量のデータを格納するクラスです。

Class A
{
   private:
      unordered_map<string, BigData> m_map;   // lots of data

   public:

    vector<BigData>   get10BestItems()
    {
        vector<BigData>  results;
        for ( ........  // iterate over m_map and add 10 best items to results
        // ... 
       return results;
    }

};

アクセサget10BestItemsは、最初にアイテムを結果ベクトルにコピーし、次に関数が返されるときに結果ベクトルがコピーされるため(関数スタックからコピー)、このコードではあまり効率的ではありません。

さまざまな理由から、c__に参照のベクトルを含めることはできません。これは明らかな答えです。

vector<BigData&> results;     // vector can't contain references.

ヒープ上に結果ベクトルを作成し、その参照を渡すことができます。

vector<BigData>&   get10BestItems()    // returns a reference to the vector
    {
        vector<BigData>  results = new vector<BigData>;   // generate on heap
        for ( ........  // iterate over m_map and add 10 best items to results
            // ... 
       return results;   // can return the reference 
    } 

ただし、注意しないと、メモリリークの問題が発生します。また、低速(ヒープメモリ)であり、マップからベクターにデータをコピーします。

したがって、cスタイルのコーディングを振り返り、ポインタを使用することができます。

vector<BigData*>   get10BestItems()    // returns a vector of pointers
    {
        vector<BigData*>  results ; // vectors of pointers
        for ( ........  // iterate over m_map and add 10 best items to results
        // ... 
       return results;  
    } 

しかし、ほとんどの情報源は、絶対に必要でない限り、ポインターを使用しないと言っています。smart_pointersとboostptr_vectorを使用するオプションがありますが、可能であればこれらを避けるようにしています。

マップが静的になることはないので、悪いポインタについてはあまり心配していません。ポインタを処理するためにコードを異ならせる必要がある場合の問題は1つだけです。様式的には、これは快適ではありません。

const BigData&   getTheBestItem()    // returns a const reference
{
       string bestID;
       for ( ........  // iterate over m_map, find bestID
       // ... 
       return m_map[bestID] ; // return a referencr to the best item
}


vector<BigData*>   get10BestItems()    // returns a vector of pointers
{    
        vector<BigData*>  results ; // vectors of pointers
        for_each ........  // iterate over m_map and add 10 best items to results
        // ... 
       return results;  
 };

たとえば、単一のアイテムが必要な場合は、参照を簡単に返すことができます。

最後のオプションは、ハッシュマップを公開し、キーのベクトル(この場合は文字列)を返すことです。

Class A
{
      public:

         unordered_map<string, BigData> m_map;   // lots of data



    vector<string>   get10BestItemKeys()
    {
        vector<string>  results;
        for (........  // iterate over m_map and add 10 best KEYS to results
        // ... 
       return results;
    }

};



A aTest;
... // load data to map

vector <string> best10 =  aTest.get10BestItemKeys();
for ( .... // iterate over all KEYs in best10
{
    aTest.m_map.find(KEY);  // do something with item.
    // ...
} 

最善の解決策は何ですか?スピードは重要ですが、開発のしやすさと安全なプログラミングの実践が必要です。

4

4 に答える 4

3

マップが定数の場合は、ポインターのベクトルを使用します。データが変更されるのを避けたい場合は、いつでも const ポインターを返すことができます。

参照は機能する場合に最適ですが、まだポインターがあるのには理由があります (私にとって、これは「必要」のカテゴリに分類されます)。

于 2013-02-08T17:51:30.030 に答える
2

私は次のようなことをします:

Class A
{
private:
    unordered_map<string, BigData> m_map;   // lots of data
    vector<BigData*> best10;

public:
    A()
        : best10(10)
    {
        // Other constructor stuff
    }

    const vector<BigData*>&   get10BestItems()
    {
       // Set best10[0] through best10[9] with the pointers to the best 10
       return best10;
    }

};

いくつかのことに注意してください。

  • ベクトルは毎回再割り当てされるのではなく、定数参照として返されるため、 を呼び出すときに何も割り当てられたりコピーされたりしませんget10BestItems

  • この状況では、ポインターは問題ありません。ポインターを回避することについて読んだことは、おそらくヒープ割り当てに関連していた可能性がありstd::unique_ptrますstd::shared_ptr

于 2013-02-08T17:51:23.187 に答える
1

これは私にとって仕事のように聞こえboost::refます。元のコードを少し変更するだけです。

typedef std::vector<boost::ref<BigData> > BestItems;

BestItems  get10BestItems()
    {
        BestItems  results;
        for ( ........  // iterate over m_map and add 10 best items to results
        // ... 
       return results;
    }

これで、概念的には戻りベクトル内の各項目への参照のみを返すようになり、コピーが小さくて安価になります (コンパイラが戻りコピーを完全に最適化できない場合)。

于 2013-02-08T17:59:43.450 に答える