2

次のコードは、XPSP3 の VC++ 8 で正しくコンパイルされますが、実行するとランタイム エラーが発生します。

私のヘッダーは次のようになります。

#include <stdexcept>
#include <iterator>
#include <list>


template<typename T>
class test_generator
{
    public:
    typedef T result_type;

    //constructor
    test_generator()
    {
        std::generate_n( std::back_inserter( tests ), 100, rand );
        value = tests.begin();
    }

    result_type operator()( void )
    {
        if( value == tests.end() )
        {
            throw std::logic_error( "" );
        }

            return *value++;
    }

    private:

    std::list<T> tests;
    typename std::list<T>::iterator value;

};

私の実装は次のようになります。

#include <functional>
#include <algorithm>
#include <iostream>
#include <deque>

#include "test.h"

int main()
{
    test_generator<double> test;
    std::deque<double> tests;

    std::generate_n( std::back_inserter( tests ), 10, test );

    return 0;
}

これは正常にコンパイルされ、例外が生成されます (ヘッダーで定義された logic_error 例外ではありません)。

ファンクターの代わりに関数を使用するように実装を変更すると、機能します。

int main()
{
    std::deque<int> tests;
    std::generate_n( std::back_inserter( tests ), 10, rand );

    return 0;
}

ここでファンクターを使用することの何が問題になっていますか?

4

2 に答える 2

4

test_generatorコンストラクターは、反復子を初期化しvalueて、testsリスト内の最初の要素 (のメンバーtest_generator) を参照します。

を呼び出すとstd::generate_n、 のコピーtestが作成されます (オブジェクトが値渡しされるため)。コピーされたオブジェクトでは、value反復子はtestsコピーではなく、元のオブジェクトのリストを参照します。

Visual Studio STL 実装で実行されるイテレーターのデバッグ チェックにより、これはアサーションをトリガーします。これは、あるコンテナーから取得したイテレーターを別のコンテナーのイテレーターと比較してはならないためです。

この問題を解決するには、クラスのコピー コンストラクターを実装するか、最初に呼び出されるまでtest_generator初期化を延期します。valueoperator()

于 2008-10-23T20:18:20.390 に答える
0

これまでのところ、例外の原因はわかりませんが、に含めることをお勧めreturn *value++しますoperator()。:-)

于 2008-10-23T20:04:40.057 に答える