4

Nicolai Josuttis の「C++ 標準ライブラリ」

第 9 章: STL イテレータは次のように述べています。

以下は、一部のプラットフォームではコンパイルできない場合があります。

std::vector <int> coll;

//sort, starting with second element
//- NONPORTABLE version

if (coll.size() > 1){
   std::sort(++coll.begin(),col.end());
}

プラットフォームによっては、++col.begin() のコンパイルが失敗する場合があります。ただし、ベクトルではなく両端キューを使用すると、コンパイルは常に成功します。... ... ユーティリティ関数 next() および prev() は、コードの移植性を考慮して C++11 で提供されます。

誰かがこの動作を説明できますか?

MINGW gcc 4.6.1、Windows OS で次の正しい出力が得られました。

std::vector<int> coll ;
for (int i=15; i>=1; i--)
 coll.push_back(i); 

sort(++coll.begin(),coll.end());
4

3 に答える 3

3

この潜在的な問題の理由は、Josuttis によって非常によく説明されています。

この奇妙な問題の理由は、ベクトル、arrays、および文字列の反復子が通常のポインターとして実装される可能性があるという事実にあります。また、ポインターなどのすべての基本的なデータ型については、一時的な値を変更することはできません。ただし、構造体とクラスの場合は許可されます。

言い換えれば、std::vector<int>::iteratorがクラスとして定義されているか、単にtypedeffor であるかによってすべてが異なりint*ます。どちらも標準で許可されているため、一部のコンパイラでは問題が発生する可能性がありますが、他のコンパイラでは発生しない可能性があります。

呼び出すとcoll.begin()、右辺値std::vector<int>::iteratorが作成されます。std::vector<int>::iterator実装されたプレフィックスを持つクラスの場合operator++、右辺値の変更が許可され、コンパイルされます。ただし、これstd::vector<int>::iteratorは int へのポインターの typedef であり、基本型の右辺値であるため、コンパイルできない場合があります。

于 2013-07-20T16:35:38.723 に答える
1

Josuttis は、 is の場合に常に定義済みの動作であることについて技術的に間違っています++container.begin()。標準はコンテナ型に対して変更可能な左辺値を返すことを保証していません。彼が「常に成功する」と言うとき、彼の本当の意味は「私が知っているすべての実装で成功する」ということであり、まったく同じではありません。containerstd::dequecontainer.begin()

公平を期すために、C++11 より前はconst、クラス型の非オブジェクトがその操作を左辺値に制限することは不可能でしたが、近い将来、代入、インクリメント、基本型との一貫性のために右辺値を減らします。

于 2013-07-20T19:05:37.243 に答える
0

++左辺値を返す場合の戻り値で実行できvector::begin()ます-本質的に、オーバーロードされたオブジェクトタイプ++ operatorです。vector::iterator標準がそれをどのように実装すべきかを主張しているとは思いません。準拠する C++ 標準ライブラリはvector::iteratorポインターとして実装できます。つまり、 for vector<T>vector<T>::iteratorbe の可能性がありますT*。この場合、戻り値が右辺値であり、右辺値をインクリメントできないため、++ 操作はコンパイルされません。

現在使用している C++ ライブラリは、オーバーロードされた&vector::iteratorを持つオブジェクトとして実装されているため、機能します。++しかし、それはそれがポータブルであることを意味しません。

このプログラムを試す

class iter
{
    int * p_;

    public:
    iter(int * p):p_(p) {}

    iter & operator ++()
    {
        ++p_;
        return *this;
    }
};
class A
{
    int * p_;

    public:
    typedef int * iterator;
    typedef iter miterator;

    iterator get()
    {
        return p_;
    }

    miterator ret()
    {
        return miterator(p_);
    }

};


int main(int argc, char **argv)
{
    A a;

    ++a.get(); // Doesn't compile

    A::iterator i = a.get();
    ++i; // compiles

    ++a.ret(); //compiles
}
于 2013-07-20T16:38:33.873 に答える