2

SpecialArray標準の 2 次元配列と同じ方法でアクセスできるクラスがあります。すなわち、としてA[i][j]intこのオブジェクトからの 1 次元配列を抽出する必要があることがよくあります。渡された他のパラメーターに依存する抽出の詳細は重要ではありません。操作のインターフェースの設計に興味があります。

このタスクを達成するための次のアプローチの利点と欠点は何ですか?

オプション1

関数を定義します。

std::vector<int> extract(const SpecialArray &A, ...)

ここ...で、1 次元配列の内容を決定する他のパラメーターを参照し、次のように使用します。

std::vector<int> output = extract(A,...);

オプション 2

std::vector から継承し、それ自体を構築するクラスを作成します。

class SpecialArrayExtract : public std::vector<int> {
    public:
        SpecialArrayExtract(const SpecialArray &A, ...);
};

ここで、コンストラクター (または同等のinit関数) は...入力を使用*thisして適切なデータを入力し、次のように使用します。

SpecialArrayExtract output(A,...);

オプション 3

オプション 2 とまったく同じように進めますが、継承せずstd::vector<int>、代わりに必要に応じて公開されたインターフェイスを持つprivateメンバーを持ちます。std::vector<int>

class SpecialArrayExtract {
    private:
        std::vector<int> m_data;
    public:
        SpecialArrayExtract(const SpecialArray &A, ...);
        [Wrapper functions for std::vector<int> here.]
};

解説

アプリケーションは高性能ですが、オプション 1 の RVO では、これらはすべて同等に機能するはずだと思います。

これをタイトルに結び付けると、私が理解しようとしているポイントは、オプション 2 と 3 の両方が、本質的にstd::vector<int>別の名前と特別なコンストラクターを持つクラスを定義するということです。いつ、もしも!-- これは合理的な考えですか? また、どちらがより良い方法ですか?

4

4 に答える 4

2
template < typename OutIt >
void extract(SpecialArray const&, OutIt dest_begin);

This works on any container, for any kind of pre-allocation of the container where the result is stored.

If you write the elements successively (à la push_back), you can use a back_insert_iterator to resize the container if necessary, but this will resize e.g. a vector if not large enough, which results in some performance impact. Otherwise, you might want to use a Random Access Iterator (doesn't change the function template signature, maybe change name from OutIt to RAIt).

You might want to add a (member) function to get the required size for pre-allocation (member if it has to access private data members).

std::size_t extract_size() const;

Example:

SpecialArray my_special;

constexpr std::size_t len = 100;
int                  dest_ra[len];
std::array<int, len> dest_a;
std::vector<int>     dest_v;
std::list<int>       dest_l;

if( len >= my_special.extract_length() )
{
    extract( my_special, std::begin(dest_ra) );
    extract( my_special, std::begin(dest_a) );
}

// using `push_back`:
  dest_v.reserve( my_special.extract_length() );       // not necessary
  extract( my_special, std::back_inserter(dest_v) );

  extract( my_special, std::back_inserter(dest_l) );

// if random access is required, also a bit faster(*):
  dest_v.resize( my_special.extract_length() );
  extract( my_special, std::begin(dest_v) );

  // not possible for the list

(*) back_insert_iterator has to do range checks in order to enlarge the vector. If you use an ordinary iterator, there are no range checks.


I like Arrieta's argumentation and agree on the judgement of the options.

于 2013-05-01T20:59:21.557 に答える
0

I would personally just implement a ToVector(...) method inside the SpecialArray class. If you dont have access to the source code (which I believe you do) you can add the method as extension to that class.

As far as I understand your problem is that you do have a SpecialArray in memory and you want to convert it to std::vector. If both of these classes are isolated in memory (i.e. there is no caching in place to increase the conversion performance) then you only need one method that grabs a SpecialArray and converts it to a std::vector. Doesnt matter if it is a Constructor or a regular method as long as the SpecialArray is passed by reference.

于 2013-05-01T20:58:37.513 に答える