2016-06-30 6 views
2

ファイルからmapに読み込むデータが大量にあります。マップからシリアライズされているため、並べ替え順になっています。 最初にデータをvectorにロードしてから、mapに一括ロードしてinsertにする方が早いことがわかりました。これにより、19秒の読み込み時間でわずか1秒を節約できます。STL map :: insertサポートはmove_iteratorsでセマンティクスを移動する必要がありますか?

value_typeは、他の構造のベクターを含む構造体です。ロードが完了した後でvectorは必要ないので、私はmap::insertへの呼び出しでmove_iteratorを使用します。 MSVC 2015(VC14)を使用すると、データはマップに移動されず、代わりにconst_referenceを介してSTLコードの内側にコピーされます。

これはデータの移動を無視するための標準準拠の実装ですか?

template<typename Stream, typename Key, typename Type, typename Traits, typename Allocator> 
bool const read(Stream &is, std::map<Key, Type, Traits, Allocator> &map) 
{ 
    size_t size; 
    read(is, size); 

    std::vector<std::pair<Key, Type>> items(size); 
    for (size_t i=0; i<size; ++i) 
    { 
     auto &item = items[i]; 
     if (!read(is, item.first) || !read(is, item.second)) 
      return false; 
    } 
    map.insert(std::make_move_iterator(items.begin()), std::make_move_iterator(items.end())); 

    return !!is; 
} 

私は

for (auto &item : items) 
    map.insert(std::move(item)); 

map.insertを交換し、問題を克服しましたが、それはとてもきちんとしていないが、別の0.6秒を保存しません。

答えて

3

これはデータの移動を無視するための標準準拠の実装ですか?

標準は、そのinsert()機能のために書かれています:

が必要です:value_type*iからXEmplaceConstructibleしなければなりません。

だから、この場合には右辺値参照であるイテレータのreferenceタイプからvalue_typeを構築することが可能でなければなりません。つまり、移動専用(つまりコピー不可)のキータイプとマップされたタイプを使用できます。反復子がマップのvalue_typeに変換できる値を返す限り、動作する必要があります。

イテレータから来たrvaluesから値をマップに構築するには、コンストラクタstd::pair<const Key, Type>::pair<K2, T2>(pair<K2, T2>&&)を使用する必要があります。

これはGCCとの私の作品、およびオンラインのコンパイラを使用して、最新のVC++で:あなたがあなた自身の移動コンストラクタを指定したりAssigmentオペレータを移動している場合は

#include <vector> 
#include <map> 
#include <iterator> 

struct MoveOnly { 
    MoveOnly() = default; 
    MoveOnly(MoveOnly&&) = default; 
}; 

bool operator<(const MoveOnly&, const MoveOnly&) { return false; } 

template<typename Key, typename Type, typename Traits, typename Allocator> 
void read(std::map<Key, Type, Traits, Allocator> &map) 
{ 
    std::vector<std::pair<Key, Type>> items(1); 
    map.insert(std::make_move_iterator(items.begin()), std::make_move_iterator(items.end())); 
} 

int main() 
{ 
    std::map<MoveOnly, MoveOnly> m; 
    read(m); 
} 
0

、その後、あなたは「noexcept」としてそれをマークする必要があります。それ以外の場合、標準コンテナは要素をコピーします。 ここでドキュメントを確認してください:http://en.cppreference.com/w/cpp/language/noexcept_spec

+0

これは 'std :: vector'に当てはまりますが、マップに挿入するためのものではありません。 –

+0

それは本当ではありません。私は彼らがstd :: vectorを例として挙げたと信じています:)ここに別のリンクhttp://en.cppreference.com/w/cpp/language/move_constructorがあります。注意部分は言う:強力な例外保証を可能にするために、ユーザー定義の移動コンストラクターは例外をスローするべきではありません。実際、標準コンテナは通常、コンテナ要素を再配置する必要があるときに、moveとcopyの間で選択するためにstd :: move_if_noexceptに依存します。 – klimov

+3

@klimov: gcc std :: libを生きている人と議論していることに注意してください! :-) –

関連する問題