CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    problem implementing 'type erasure'

    I am playing around with 'type erasure' (see these links: https://akrzemi1.wordpress.com/2013/...rasure-part-i/, http://www.artima.com/cppsource/type_erasure2.html).
    For this purpose, I created a project where I want a class to be able to access a std::map, regardless of the map's exact type.

    The type erasure part consists of the interface IteratorBase, the wrapper to concrete classes, IteratorWrapper, which implements IteratorBase and forwards the interface calls to calls of the concrete class it wraps, and finally the type erasure class itself, Iterator, which holds a pointer to IteratorBase, which is polymorphically an instance of IteratorWrapper.

    The test class foo instanciates a map in its constructor, its type being a template argument.

    Everything works as I want it to, as long as I provide the virtual destructor of IteratorBase.
    At first, I missed that d'tor, and then the program crashes somewhere deep in the std::map's destructor.
    Is this just 'undefined behaviour' or does someone have a better explanation?

    I hope the code is not overly complicated.


    Code:
    #include <memory>
    #include <map>
    #include <iostream>
    
    template<typename IteratorType>
    class IteratorBase
    {
    public:
        virtual bool operator==(const IteratorBase& other) const = 0;
        virtual bool operator!=(const IteratorBase& other) const = 0;
        virtual IteratorBase& operator++() = 0;
        virtual IteratorType& operator->() = 0;
        virtual ~IteratorBase() {}
    };
    
    template<typename IteratorType>
    class IteratorWrapper : public IteratorBase<IteratorType>
    {
    public:
        IteratorWrapper(const IteratorType& it) : it(it) {}
        virtual bool operator==(const IteratorBase& other) const override { return it == static_cast<const IteratorWrapper<IteratorType>&>(other).it; }
        virtual bool operator!=(const IteratorBase& other) const override { return !(*this == other);  }
        virtual IteratorBase& operator++() override { ++it; return *this; }
        virtual IteratorType& operator->() override { return it; }
    
    private:
        IteratorType it;
    };
    
    template<typename IteratorType>
    class Iterator
    {
    public:
        template<typename IteratorType>
        Iterator(const IteratorType& it) : base(new IteratorWrapper<IteratorType>(it)) {}
        bool operator==(const Iterator& other) const { return *base == *other.base; }
        bool operator!=(const Iterator& other) const { return !(*this == other); }
        Iterator(const Iterator&);
        Iterator& operator=(const Iterator&);
        Iterator& operator++() { ++(*base); return *this; }
        IteratorType& operator->() const { return (*base).operator->(); }
    
    private:
        std::unique_ptr<IteratorBase<IteratorType>> base;
    };
    
    template<typename K, typename T, typename I>
    class Map
    {
    protected:
        using key_type = K;
    
    public:
        virtual Iterator<I> begin() = 0;
        virtual Iterator<I> end() = 0;
    
        virtual void insert(const key_type& key, int* val) = 0;
    };
    
    class Map1 : public Map<int, int*, std::map<int, int*>::iterator>
    {
        using iterator = std::map<int, int*>::iterator;
    
    public:
        virtual Iterator<iterator> begin() override { return Iterator<iterator>(m.begin()); }
        virtual Iterator<iterator> end() override { return Iterator<iterator>(m.end()); }
        virtual void insert(const key_type& key, int* val) override { m.insert(std::make_pair(key, val)); }
    
    private:
        std::map<int, int*> m;
    };
    
    class Map2 : public Map<int, std::shared_ptr<int>, std::map<int, std::shared_ptr<int>>::iterator>
    {
        using iterator = std::map<int, std::shared_ptr<int>>::iterator;
    
    public:
        virtual Iterator<iterator> begin() override { return Iterator<iterator>(m.begin()); }
        virtual Iterator<iterator> end() override { return Iterator<iterator>(m.end()); }
        virtual void insert(const key_type& key, int* val) override { m.insert(std::make_pair(key, std::shared_ptr<int>(val))); }
    
    private:
        std::map<int, std::shared_ptr<int>> m;
    };
    
    template<typename M>
    class foo
    {
    public:
        foo() : m(std::make_unique<M>())
        {
            for (auto i = 0; i < 10; ++i)
            {
                m->insert(i, new int());
            }
        }
    
        void func()
        {
            for (auto it = m->begin(), endIt = m->end(); it != endIt; ++it)
            {
                std::cout << *it->second << std::endl;
            }
        }
    
    private:
        std::unique_ptr<M> m;
    };
    
    int main()
    {
        foo<Map1> f;
        f.func();
    
        foo<Map2> f2;
        f2.func();
    }

  2. #2
    VictorN's Avatar
    VictorN is offline Super Moderator Power Poster
    Join Date
    Jan 2003
    Location
    Hanover Germany
    Posts
    20,396

    Re: problem implementing 'type erasure'

    Victor Nijegorodov

  3. #3
    Join Date
    May 2001
    Location
    Germany
    Posts
    1,158

    Re: problem implementing 'type erasure'

    Well, I know a bit about virtual destructors. What I don't understand is how a class that wraps an iterator influences the destruction of the map. How are these things related?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured