2011-12-04 3 views
7

STLアルゴリズムを使用してこれを行うにはどうすればよいですか?copy_nまたはeofまで

std::ifstream file(filename); 

std::vector<unsigned char> buf; 
for(auto file_it = std::istreambuf_iterator<char>(file); file_it != std::istreambuf_iterator<char>() && buf.size() < 2048; ++file_it) 
    buf.push_back(*file_it); 

buf.size() < 2048

次のようにすれば、ファイルは2048バイトよりも小さくなりますが、どうなりますか?ドキュメントと同様に

std::copy_n(std::istreambuf_iterator<char>(file), 2048, std::back_inserter(buf)); 
+0

ファイルが大きくなるとどうなりますか?残りの部分は破棄されていますか、まだ読み込まれている部分の先頭にイテレータが必要ですか? – pmr

+0

必要なバイト数が読み込まれると、ifstreamは破棄されます。 – ronag

+0

これは、アルゴリズムの代わりに独立したイテレータを持つ可能性を開きます。 – pmr

答えて

1

std::copy_n()正確nアイテムをコピーします、と言います。イテレータが参照するシーケンスの終わりを過ぎても読み取りを続けます。しかし、標準が何についてistreambuf_iterator<>と言うのか分かりません。これはおそらく未定義の動作ですが、ストリームの末尾にはeof()という多数のコピーが生成される可能性があります。これは、2048バイト未満が利用可能な場合、多くのゴミにつながる可能性があります。

あなたは確実にnまでの項目をコピーしたい場合はいずれの場合も、あなたがあなた自身の関数を記述する必要がありますが:

template<typename I1, typename I2, typename size_type> 
I copy_upto_n (I1 begin, I1 end, size_type n, I2 out) 
{ 
    for (size_type i=0; (i < n) && (begin != end); ++i) 
    { 
     *out++ = *begin++; 
    } 
    return out; 
} 

一部の人々はstd::iterator_traits<>の代わりに、余分なテンプレートパラメータにを使用する場合がありますイテレータと同じ距離の型を強制します。

+0

+1一般的なイテレータアルゴリズムと 'std :: iterator_traits'の言及。 –

+0

'out'はおそらく別のテンプレート引数でなければなりません。 – pmr

+0

@ pmr:確かに。これがなければ、質問に投稿されたユースケース(例えば、 'std :: back_inserter()'を使って)ではうまくいきません。コードを編集します。 –

0

述語に基づいて操作を破棄する特殊なback_insert_iteratorを使用できます。

このコードは、st35libの のGCC実装から恥知らずに採り入れられています。 C++ 03バージョンでは、割り当てに Container::const_referenceが必要です。

template<typename Container, typename Predicate> 
class discarding_back_inserter 
    : public iterator<output_iterator_tag, void, void, void, void> 
{ 
    Container* container; 
    Predicate p; 
public: 
    typedef Container   container_type; 

    explicit 
    back_insert_iterator(Container& x, Predicate p) : container(&__x), p(p) { } 

    back_insert_iterator& 
    operator=(const typename Container::value_type& value) 
    { 
     if(*container) 
     container->push_back(__value); 
     return *this; 
    } 

    back_insert_iterator& 
    operator=(typename _Container::value_type&& value) 
    { 
     if(*container) 
     container->push_back(std::move(__value)); 
     return *this; 
    } 

    back_insert_iterator& 
    operator*() 
    { return *this; } 

    back_insert_iterator& 
    operator++() 
    { return *this; } 

    back_insert_iterator 
    operator++(int) 
    { return *this; } 
}; 
+1

これを個人的にとらないでください。 –

+0

@BenjaminLindley Nah、決して。アルゴリズムを変更する反対のアプローチを探す価値はありますが、それだけです。結果は、コンテナ上で動作するため、あまり汎用的ではありません。 'Maybe'値に基づいて' generate'のバージョンを用意したいと思っています。それは本当に簡単になります。 – pmr

+0

これは述語をまったく使用しません。述語がストリームへのポインタを格納していて、それがeofをチェックできるようにするとうまくいくかもしれません。値の引数はあまり情報を与えません。 – UncleBens

関連する問題