3

myvector.start()とmyvector.end()が与えられた場合、データをコピーせずにmyvectorの読み取り専用サブセットを作成したいと思います

これは可能ですか、そしてどのように?

#include <iostream>
#include <vector>

using namespace std;

template <class T> void print_vector(const vector<T> &v) {
    for(size_t i = 0; i < v.size(); ++i) std::cout << v[i] << " ";
    std::cout << std::endl;
}

int main() {

まず、ベクトルを作成します。

    vector<double> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    print_vector(data); // 1 2 3 4 5 6 7 8 9 10

次に、サブセットが必要です。しかし、これはコピーになると思います。

    // Does this make a copy or not? I don't want to make a copy.
    const vector<double> subset1(data.begin() + 3, data.end() - 3);
    print_vector(subset1); // 4 5 6 7

このアプローチはどうですか?

    // Another approach. Questions:
    // - Would something like this be a good alternative if I really don't want a copy?
    // - How would the performance of this be compared to a normal STL container?
    // - Is there an existing implementation of a container that does something like this, maybe a boost class?
    class SubsetType {
    public:
        SubsetType(const vector<double>::iterator &start, const vector<double>::iterator &end) { begin_ = start; end_ = end; }

        vector<double>::iterator begin() { return begin_; }
        vector<double>::iterator end() { return end_; }

        double operator[](vector<double>::size_type i) { return *(begin_ + i); }

        vector<double>::size_type size() { return end_ - begin_; }

    private:
        vector<double>::iterator begin_, end_;
    };

    SubsetType subset2(data.begin() + 3, data.end() - 3);
    for(size_t i = 0; i < subset2.size(); ++i) std::cout << subset2[i] << " ";
    std::cout << std::endl; // 4 5 6 7

または、f(const vector :: iterator&start、const vector :: iterator&en)のようなすべての関数を宣言するソリューションです。STLアルゴリズムはこれを行いますよね?(ただし一般的)

出口

    std::cout << "Bye!" << std::endl;
    return 0;
}
4

5 に答える 5

2

イテレータ(適切な場合はconst)を使用するだけです。

開始/終了ペアをどこにでも渡すことに本当にアレルギーがある場合は、Boost.Range[start,end)または同様のものを使用することを検討してください。ペアを単一のオブジェクトにバンドルできます。

于 2012-10-11T22:21:47.853 に答える
1

コピーが必要ない場合は、std ::アルゴリズムライブラリと同じイディオムに従い、開始と終了のイテレータを利用します。イテレータは軽量であり、コピー操作のコストを負担しません。

于 2012-10-11T22:19:33.580 に答える
1

C ++ 11では、すべてのコンテナーがcbegin()and関数を取得します。これにより、非constコンテナーからでもscend()を作成できます。const_iteratorその後、アルゴリズムを修正して開始と終了のイテレータを受け入れるだけで、完了です。

print_range(data.cbegin()+3, data.cend()-3);

C ++ 03で立ち往生している場合は、任意のオブジェクトをそのconstバージョンに変換するライト転送関数を使用できます。

template<class T>
T const& as_const(T const& v){ return v; }

その後:

print_range(as_const(data).begin()+3, as_const(data).end()-3);
于 2012-10-11T22:21:26.070 に答える
1

または、f(const vector :: iterator&start、const vector :: iterator&en)のようなすべての関数を宣言するソリューションです。

はい。

STLアルゴリズムはこれを行いますよね?(ただし一般的)

はい。一般的にもそれを行います。標準ライブラリアルゴリズムは、モデル化するのに非常に良い例です。

于 2012-10-11T22:21:49.153 に答える
1

ブースト範囲はあなたが意図したものに近いでしょう。

以下のサンプルは、

  • スライスされたアダプタを使用して、ベクトルのサブレンジ「ビュー」を作成します(コピーなし)
  • 元の(基になる)ベクトル要素を変更すると、そのビューのデータが変更されることを示しています
  • make_iterator_rangeほぼ同じことを行うために使用します。

アダプタは、単純なイテレータ範囲よりもはるかに柔軟な抽象化であることに注意してください。

#include <boost/range/adaptors.hpp>
#include <boost/range/algorithm.hpp>
#include <vector>

using namespace boost::adaptors;

int main(int argc, const char *argv[])
{
    std::vector<int> v { 0, 1, 2, 3, 4, 5, 6 };

    auto output = std::ostream_iterator<int>(std::cout, ",");

    auto&& slice = v | sliced(2, 5);

    boost::copy(slice, output); 
    std::cout << '\n';

    v[3] += 10;

    boost::copy(slice, output); 
    std::cout << '\n';

    /// Alternative without adaptors:

    auto range = boost::make_iterator_range(v.begin()+3, v.end());

    boost::copy(range, output); 
    std::cout << '\n';
}

http://liveworkspace.org/code/5be869c15f534b6161e61c392c181f2dでライブでご覧ください

実行出力:

2,3,4,
2,13,4,
13,4,5,6,
于 2012-10-11T22:22:24.363 に答える