2

私はあなたに私の問題を提示します

私は2つのリストを持っており、それらにAとBという名前を付けています。

list<vector<int> > A = {{1},{2},{3}};
list<vector<int> > B = {{4},{5},{6}}; 

私が欲しいのは、A = {{1,4}、{1,5}、{1,6}、{2,4}、{2,5}、{2,6}、{3,4}にすることです、{3,5}、{3,6}}tmpリストを使用しません。

Ubuntu12.04でgcc4.6.3でC++11を使用しています

コードを最小化するために:

auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i); // A[i]
        copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
        A.emplace_back(tmp); //add it to A
    }
}
A.erase(A_begin,A_end); // remove {1},{2},{3}

ですから、アルゴは大丈夫だと思いますが、Aで無限ループを作ります。A.emplace_backを作成するとA_endが変化すると思いますが、保存しているので、ここにwatを追加するのは本当にわかりません。

問題を特定するための私のコード:

auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();

int ii = A.size();

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i);
        A.emplace_back(tmp);
    }
    cout<<--ii<<endl; // exit when print 0 ?
}

これは負の数を出力します、そして私は再び^Cしなければなりません。

編集:私は解決策を見つけます:

auto A_begin = A.begin();
auto A_end =  A.end();
auto B_begin = B.begin();
auto B_end = B.end();

list<vector<int>> tmp_l;

for(auto i = A_begin; i != A_end; ++i) //loop on A
{
    for (auto j = B_begin;j != B_end; ++j) //loop on B
    {
        vector<int> tmp = (*i); // A[i]
        copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
        tmp_l.emplace_back(move(tmp)); //add it to A
    }
}
 swap(tmp_l,A);
4

3 に答える 3

2

これらの 2 行:

vector<int> tmp = (*i); // A[i]
copy((*j).begin(),(*j).end(),tmp.end()); // append B[j] to A[i]

未定義の動作を呼び出します。tmp.end() にコピーすると、A[i] を拡張するのではなく、A[i] の終了後にメモリを上書きするだけです。次のような back_insert イテレータを使用する必要があります。

vector<int> tmp = (*i); // A[i]
copy((*j).begin(), (*j).end(), back_inserter(tmp)); // append B[j] to A[i]

back_inserter を取得するには、ヘッダーも含める必要があります。

編集: また、 A_end イテレータはリストの「最後を過ぎた」位置を指しているため、 a に追加するアイテムの数に関係なく、常に A_end の前に追加されるため、無限ループが発生します。これに対処する良い方法があるかどうかはわかりません。ここでは、一時リストを作成しないことに利点はありません。どちらの方法でも同じメモリを割り当てているため、新しいリストに書き込むだけです。

于 2013-01-18T13:13:21.510 に答える
1

編集:私は解決策を見つけます:

その解決策は良いです.一時的なベクトルを使用してそれを交換することAは、元のバージョン(およびベクトルの終わりを越えてコピーすること)がすべての要素を移動する最初から終了するため、その場で行うよりも優れています.erase

しかし、あなたのソリューションは改善することができます:

// get rid of these iterators, they're useless
/*
auto A_begin = A.begin();
auto A_end =  A.end();
auto B_begin = B.begin();
auto B_end = B.end();
*/

list<vector<int>> tmp_l;

// use new for loops
for (auto& a : A)
{
    for (auto& b : B)
    {
// use auto
        auto tmp = a; // A[i]
// I find just inserting at the end simpler than using `back_inserter`
        tmp.insert(tmp.end(), b.begin(), b.end()); // append B[j] to A[i]
// then clear it the moved-from elements:
        b.clear();
// move the tmp vector into place, do not copy it.
        tmp_l.emplace_back(std::move(tmp));
    }
}
swap(tmp_l,A);
于 2013-01-18T14:01:09.010 に答える
1

あなたのアルゴリズムは良くありません。

これ :

copy((*j).begin(),(*j).end(),tmp.end());

ランダムなメモリを上書きするため、あらゆる種類の問題が発生します。

おそらく、追加するために次のようなことをしたいと思っていました:

vector<int> tmp = (*i);
copy((*j).begin(),(*j).end(),std::back_inserter(tmp));
于 2013-01-18T13:07:48.077 に答える