2

我遇到了无法识别的特定内存泄漏问题。记忆的演出。

在这种特殊情况下,所有对象都在堆栈上(尽管大多数确实在堆上创建了一些东西)。这些对象的生命周期很短,并且在大多数情况下都存在于 for 循环中。我不知道到底发生了什么,但他们积累的尸体留在了记忆中。我已经做了足够多的调试来确定它们的创建(以及随后从内存中删除的失败)是造成内存浪费的原因。

通过相当多的测试,我已经验证了构造函数被调用的次数等于析构函数被调用的次数。其中一个类是虚拟类,所以我确保它的析构函数是虚拟的(它是)。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

4

我已经弄清楚发生了什么。内存问题是由于我仍在 Boost::flat_map 和朋友中追踪的一个错误,其中 flat_map.insert(iterator,iterator) 导致内存泄漏。但是,我没有认出它,因为我调用了 flatmap(const &flatmap)。我猜它仍然会做同样的事情。

于 2013-09-12T16:33:40.787 回答