2

識別できない特定のメモリ リークに問題があります。思い出のギグ。

この特定のケースでは、すべてのオブジェクトがスタック上にあります (ただし、ほとんどはヒープ上に何かを作成します)。オブジェクトの存続期間は非常に短く、ほとんどの場合、for ループ内で存続します。何が起こっているのか正確にはわかりませんが、彼らの蓄積された死体は記憶に残っています. それらの作成 (およびその後のメモリからの削除の失敗) がメモリの浪費の原因であると判断するのに十分なデバッグを行いました。

かなりのテストを通じて、コンストラクターが呼び出される回数とデストラクタが呼び出される回数が等しいことを確認しました。クラスの 1 つは仮想クラスなので、そのデストラクタが仮想であることを確認しました (仮想でした)。Valgrind はメモリ リークを指摘していません。他に何を試すべきかわかりません。私はほとんどコンパイラのバグにぶつかっていると思っていますが、通常、それは私が間違っていることを意味します.

誰かが私を助けることができれば、私はそれを大いに感謝します!

以下は、私が使用している基本的なクラスです。それらを使用して、C++ でジェネレーターの概念を再作成しました。これらは、私のプログラム全体の核心です。

/**
 * @file    generator.hpp
 * @brief   Macros and class to create generators
 *
 * @author  Adam Baxter
 * @version 2.0
 * @date    2012/07/11
 * @copyright 2012
 */

#ifndef apollo_generator_hpp_
#define apollo_generator_hpp_

/**
 * @brief A macro to define the beginning of a generator's operator() function
 */
#define $gen_start if(_line < 0) { _line = 0;} \
switch(_line) { case 0:;

/**
 * @brief A macro to define the end of a generator's operator() function
 */
#define $gen_stop  } _line = 0; return false;

/**
 * @brief A macro to yield the generator's current position and create that corrosponding return value
 */
#define $yield(R)    \
do { \
    _line = __LINE__; \
    generate(R); return true; case __LINE__:; \
} while (0);

namespace apollo {

/**
 * @class   Generator generator.hpp "generator.hpp"
 * @brief   Standard generator interface for all generators in this project.

     The macros above, coupled with this class, are used to define functions that can be jumped into and out at arbitrary positions

    Consider NumGen, a simple number generator:

    class NumGen : public Generator<int> {

    NumGen() : _i(0), Generator<int>() {}

    bool operator()(value_type &rv) {
        $gen_start;
        for(_i = 0; _i < 10; _i++) {
            $yield(rv);
        }
        $gen_stop;
    }

    void generate(value_type &rv) {
        rv = _i;
    }

    private:
        value_type _i;
    };

    NumGen is nothing more than a simple for-loop that yields numbers [0,10).
    The importance of the generator is to separate out the generator's next state calculation (_i++)
    from the return value's generator (rv = _i) from the rest of the application logic

    The more complex of a state we're working with, the more powerful this idea becomes. 

    @Note Successive calls to operator() will place execution directly after
        the last called yield statement
        - Any variable modification between $gen_start and $yield will be skipped! -
        A generator's state must be held in its member variables and care must be exercised when using 
        local variables in operator().
 */

template <typename T>
class Generator {
public:

    /**
     * The type the generator creates
     */
    typedef T value_type;

    // default ctor
    Generator(): _line(-1) {}

    // copy ctor
    Generator(Generator const &rhs) : _line(rhs._line) {}

    // move ctor
    Generator(Generator &&rhs) : _line(rhs._line) {}

    // copy = ctor
    Generator& operator=(Generator const &rhs)
    {
        if (this != &rhs) {
            _line = rhs._line;
        }
        return *this;
    }

    // move = ctor
    Generator& operator=(Generator &&rhs)
    {
        if (this != &rhs) {
            _line = rhs._line;
        }
        return *this;
    }

    /**
    * Generator calculates its next state, creates the value for that state.
    *
    * @param[in,out] rv The return value's storage location
    *
    * @return True if generator at next state and a new return value is generated. 
    *   False if there are no more valid states and return value is untouched.
    */
    virtual bool operator()(value_type &rv) = 0;

    /**
     * Using the generator's current state, create the return value
     *
     *  @param[in,out]  rv The return value's storage location
     */
    virtual void generate(value_type &rv) const = 0; 

    // == operator
    virtual bool operator==(Generator const &rhs) const {
        return _line == rhs._line;
    }

    // deconstructor
    virtual ~Generator() {}

protected:
    int _line; /**< The source code line $gen_start will use for its switch */
};

} /* namespace apollo */

#endif // apollo_generator_hpp_

/**
 * @file    generatoriterator.hpp
 * @brief   A class to create iterators out of generators
 *
 * @author  Adam Baxter
 * @version 2.0
 * @date    2012/07/11
 * @copyright 2012
 */

#ifndef apollo_generatoriterator_hpp_
#define apollo_generatoriterator_hpp_

#include <utility>
#include <iterator>
#include <boost/iterator/iterator_facade.hpp>

namespace apollo {

template <typename G>
class GeneratorIterator : public boost::iterator_facade <
    GeneratorIterator<G>,
    const typename G::value_type,
    boost::forward_traversal_tag> {
public:
    typedef G generator_t;

    GeneratorIterator() : _finished(true) {}

    explicit GeneratorIterator(generator_t const &gen) :
        _gen(gen),
        _finished(false) {
            this->operator++();
    }

    explicit GeneratorIterator(generator_t &&gen) :
        _gen(std::forward<generator_t>(gen)),
        _finished(false) {
            this->operator++();
    }

    GeneratorIterator(GeneratorIterator const &rhs) :
        _gen(rhs._gen),
        _finished(rhs._finished) {
            if (!_finished) {
                _gen.generate(_rv);
            }
        }

    GeneratorIterator(GeneratorIterator &&rhs) :
        _gen(std::move(rhs._gen)),
        _rv(std::move(rhs._rv)),
        _finished(rhs._finished) {}

    GeneratorIterator& operator=(GeneratorIterator const &rhs) {
        if (this != &rhs) {
            _gen = rhs._gen;
            _finished = rhs._finished;
            if (!_finished) {
                _gen.generate(_rv);
            }
        }
        return *this;
    }

    GeneratorIterator& operator=(GeneratorIterator &&rhs) {
        if (this != &rhs) {
            _gen = std::move(rhs._gen);
            _rv = std::move(rhs._rv);
            _finished = rhs._finished;
        }
        return *this;
    }

    generator_t const& gen() const {
        return _gen;
    }

    ~GeneratorIterator() {}

private:
    friend class boost::iterator_core_access;
    generator_t _gen;
    typename generator_t::value_type _rv;
    bool _finished;

    bool equal(GeneratorIterator const &rhs) const {
        if (_finished || rhs._finished) {
            if (_finished && rhs._finished) {
                return true;
            } else {
                return false;
            }
        }  else if ((_rv == rhs._rv) &&
            (_gen == rhs._gen)) {
            return true;
        }
        return false;
    }

    void increment() { advance(); }

    void advance(std::ptrdiff_t dist = 1) {
        while (!_finished && (dist > 0)) {
            if( _gen(_rv) == false) {
                _finished = true;
            }
            dist -= 1;
        }
    }

    std::ptrdiff_t distance_to(GeneratorIterator const &rhs) const {
        using std::distance;
        if (_finished && rhs._finished) {
            return 0;
        }
        if (!_finished) {
            return distance(*this, rhs);
        } else {
            return distance(rhs, *this) * -1;
        }
    }

    const typename generator_t::value_type& dereference() const { return _rv; }

};

template<class G, typename... Args>
GeneratorIterator<G> make_geniter(Args && ...args) {
    return GeneratorIterator<G>(G(std::forward<Args>(args)...));
}

} /* namespace apollo */

#endif /* apollo_generatoriterator_hpp_ */
4

1 に答える 1