0

ベクトルにファクトリ関数を使用し、以前の値を吹き飛ばすサイズ変更を呼び出さずにイテレータを使用したいですか?

それは可能ですか、それともSTL設計のポイントが欠けていますか?

#include <vector>
#include <algorithm>
#include <iostream>

struct A
{
    A():_x(42){}
    A(double x):_x(x){}
    double _x;
};

struct factory
{
    A operator()()
    {
        return A(3.14);
    }
};

int main()
{
    std::vector<A> v;
    int nbr = 3;
    v.reserve(nbr);
    std::generate_n(v.begin(), nbr, factory());

    std::cout << "Good values" << std::endl;
    for(int i = 0 ; i < nbr ; ++i)
        std::cout << v[i]._x << std::endl;

    v.resize(nbr); //How I can have the syntax below without the resize which blows my previous values ?

    std::cout << "resize has been called so values are bad (i.e default ctor)" << std::endl;
    for(std::vector<A>::iterator it = v.begin() ; it != v.end() ; ++it)
        std::cout << (*it)._x << std::endl;
}

ありがとう :)

4

4 に答える 4

8

私はあなたの懸念を完全に理解していなかったか、そうでなければあなたは誤解を招きました。resize()コンテナ内の既存の要素を変更しません(小さいサイズにサイズ変更した場合に削除された要素を除く)。

さて、あなたの実際の問題は、あなたのプログラムに未定義の振る舞いがあるということです。ベクトルは持っていますcapacity() == nbrsize() == 0、あなたが呼び出すときgenerate_n、それはコンテナの終わりを超えて書いています。これには2つの解決策があります。まず、呼び出す前にサイズを変更できますgenerate_n

std::vector<A> v;
int nbr = 3;
v.resize(nbr);
std::generate_n(v.begin(), nbr, factory());

または、イテレータのタイプを変更できます。

std::vector<A> v;
int nbr = 3;
v.reserve(nbr);
std::generate_n(std::back_inserter(v), nbr, factory());
于 2012-07-10T14:59:07.740 に答える
0
v.reserve(nbr);
std::generate_n(v.begin(), nbr, factory());

エラーです。予約!=サイズ変更、予約は必要な場合にのみメモリを割り当てます。印刷ベクトルにサイズ変更を使用するのはなぜですか?サイズ変更は、ベクトルのサイズ変更、開始/終了がサイズ変更に依存しない関数です。

于 2012-07-10T14:57:38.367 に答える
0

generate_n値をベクトルに正しく生成していません。ベクトルのサイズは0であるため、正しく機能しているように見えるかもしれませんが、ベクトルの終わりを超えて書き込むと運が良くなります。あなたは本当に使用する必要がありますresize。代わりに(そしておそらくよりパフォーマンスの高い):を使用することができますback_inserterstd::generate_n(std::back_inserter(v), nbr, factory());

于 2012-07-10T14:58:33.987 に答える
0

コードの最初の部分はすでに壊れています。ベクトル要素を作成するにはresize、ではなく、を呼び出す必要がありreserveます。reserve生のメモリを割り当てることによってのみ将来のベクトル容量を予約できますが、実際のベクトル要素を作成(構築)することはありません。通常、ベクトルのサイズとベクトルの容量の間にあるベクトル要素にアクセスすることは許可されていません。

呼び出しreserveた後、要素がすでに構築されているかのようにベクトルを使用しようとします。要素に値を割り当て、これらの値を読み取って印刷しようとします。一般的に、これは違法であり、一般的に未定義の動作につながります。その間、あなたのベクトルのサイズは残っていました0、それはあなたが後でその奇妙な呼び出しによって補償しようとしたものですresize

最初に電話する必要がありますresize。最初から適切な数の要素を持つベクトルを作成します。(これは、初期サイズをベクターのコンストラクターに渡すことによっても実行できます)。

たとえば、

int nbr = 3;
std::vector<A> v(nbr);
std::generate_n(v.begin(), nbr, factory());

また

std::vector<A> v;
int nbr = 3;
v.resize(nbr);
std::generate_n(v.begin(), nbr, factory());

これで完了です。忘れてくださいreserve-この場合は必要ありません。

于 2012-07-10T15:00:12.917 に答える