Kurz beurteilen!



  • Hilfe! Kann jemand kurz und schnell mal schauen, ob mein Code hier sauber ist? mein prof will heute noch wissen, ob ich template-programmierung verstanden habe!
    danke!



  • Code vergessen... bin durch den wind

    #include <iostream>
    #include <cstdlib>
    #include <string>
    #include <string>
    
    using namespace std;
    
    template <class T>
    class Allocator {
    
        public:
            Allocator() { }
            T* alloc() {
               return reinterpret_cast<T*>(malloc(sizeof(T)));
            }
    
            void destroy(T *obj) {
                obj->~T();
                free(obj);
            } 
    };
    
    template <class T, class Alloc = Allocator<T> >
    class Test {
      private:
            T *val;
            Alloc *alloc;
    
      public:
            Test(T param) {
                alloc = new Alloc();
                val = alloc->alloc();
                *val = param;
                std::cout << *val << std::endl;
            }
    
            ~Test() {
                alloc->destroy(val);
                delete alloc;
            }      
    
    };
    
    int main() {
        Test<string> t("Ich mag Eis.");
        system("pause");
        return 0;
    }
    


  • Hätteste statt 'kurz beurteilen' nicht irgendwas mit 'template' wählen können?
    Da kann man so was leichter widerfinden, wenn man es suchen sollte 😉

    Zu deinem eigentlichen Anliegen kann ich nicht viel beitragen, außer warum
    includierst du 'string' 2x ?



  • Was mich noch ein wenig verwirrt:
    Zeile 6 oder Zeile 34 solltest du noch mal kritisch beurteilen!

    malloc/free und new/delete im selben Quelltext gibt es da keine andere Lösung?



  • template <class T, class Alloc = Allocator<T> > 
    class Test { 
      private: 
            T *val; 
            Alloc *alloc; 
    
      public: 
            Test(T param) { 
                alloc = new Alloc(); 
                val = alloc->alloc(); 
                *val = param; 
                std::cout << *val << std::endl; 
            } 
    
            ~Test() { 
                alloc->destroy(val); 
                delete alloc; 
            }       
    };
    

    würd ich so nicht machen...

    template <class T, class Alloc = Allocator<T> > 
    class Test { 
      private: 
            T *val; 
            Alloc alloc; 
    
      public: 
            Test(T param)
            { 
                val = alloc.alloc(); 
                *val = param; //das hier ist so gar falsch...
                std::cout << *val << std::endl; 
            } 
    
            ~Test() { 
                alloc.destroy(val);
            }       
    };
    

    allocator sollte eine construct-function bereitstellen...
    hab so was auch ma für die uni gemacht - so sieht mein allocator aus:

    //includes wären
    #include <algorithm> //max
    #include <cstddef> //size_t / ptrdiff_t
    #include <new> //placement new
    
    //und namespace std_copyed kannst du mit std ersetzen, falls ihr die standard-lib verwenden dürft - wir durften es nicht und so musst ich selbst was schreiben ^^
    //kann auch sein, dass manchmal kein namespace mit davor steht, weil der allocator auch im namespace std_copyed steht^^
    
    #ifdef COMPILER_MSVC
    #	pragma warning(push, 3) //http://msdn.microsoft.com/en-us/library/26kb9fy0.aspx
    #	pragma warning(disable: 4100) //C4100 can also be issued when code calls a destructor on a otherwise unreferenced parameter of primitive type. This is a limitation of the Visual C++ compiler.
    #endif
    
    template <typename T>
    class allocator
    {
    public:
    	typedef T value_type;
    	typedef value_type* pointer;
    	typedef const value_type* const_pointer;
    	typedef value_type& reference;
    	typedef const value_type& const_reference;
    
    	typedef std_copyed::ptrdiff_t difference_type;
    	typedef std_copyed::size_t size_type;
    
    	template<class T_>
    	struct rebind
    	{
    		typedef typename allocator<T_> other;
    	};
    public:
    	allocator()
    	{}
    
    	template<typename T_>
    	allocator(const allocator<T_> &)
    	{}
    
    	pointer address(reference r) const
    	{ return &r; }
    	const_pointer address(const_reference r) const
    	{ return &r; }
    
    	pointer allocate(size_type count, allocator<void>::const_pointer = nullptr)
    	{
    		size_type object_size = sizeof(T);
    		size_type byte_count = object_size * count;
    		void* address = ::operator new(byte_count);
    		return reinterpret_cast<pointer> (address);
    	}
    
    	void deallocate(pointer p, size_type /*count*/)
    	{
    		return ::operator delete(p);
    	}
    
    	void construct(pointer p, const_reference value)
    	{
    		::new(p) T(value);
    	}
    
    	void destroy(pointer p)
    	{
    		p->~value_type();
    	}
    
    	size_type max_size() const
    	{
    		size_type addresses = size_type(~0);
    		size_type object_size = sizeof(T);
    		return max(addresses/object_size, 1); //allocate(max_size()) shall gave us a well defined behavior - and allocate(0) is undefined
    	}
    };
    
    template < >
    struct allocator <void>
    {
    	typedef const void* const_pointer;
    	typedef void* pointer;
    };
    
    template<typename T>
    void swap(typename allocator<T> &lhs, typename allocator<T> &rhs)
    { /*do nothing*/ }
    
    #ifdef COMPILER_MSVC
    #	pragma warning(pop)
    #endif
    

    benutzung wäre so in etwa:

    template< typename T, typename TAlloc = allocator<T> >
    struct x
    {
    private:
      TAlloc alloc;
      T* a;
    public:
      x()
      //: alloc() --- wird implizit aufgerufen, würd ich also weglassen ^^
      {
        a = alloc.allocate(1);
        try
        {
          alloc.construct(a, T());
        }
        catch(...)
        {
          alloc.deallocate(a, 1);
          throw;
        }
      }
    
      ~x()
      {
        alloc.deallocate(a, 1);
      }
    }
    
    int main()
    {
      x a;
      x b;
    }
    

    bb

    ich hoffe, es hilft dir ein wenig - falls nicht, dann frag einfach ^^

    edit: hatte noch was vergessen ^^



  • > *val = param; //das hier ist so gar falsch...

    Wieso? 🙂

    Dein Allokator ist ja im STL-Stil! Ich wollte das nicht soo komplex machen.



  • ok - dann machst du es eben anders ^^
    auf jeden fall passiert beim assignment operator ja im prinzip (in der praxis sieht die reihenfolge anders aus, aber das soll hier nicht stören):

    - lösche lhs
    - kopiere rhs nach lhs

    so bald T also ein typ ist, der einen destruktor besitzt, wird der aufgerufen - leider befindet sich da aber nicht wirklich ein objekt - es wurde bisher nur speicher angefordert und an der stelle steht irgendetwas...
    dafür gibt es das placement new - was hier durch construct gekapselt wird..

    dem zu folge brauchst du mindestens das hier:

    template <typename T>
    struct allocator
    {
        typedef std::size_t size_type;
    
        pointer allocate(size_type count = size_type(1))
        {
            size_type object_size = sizeof(T);
            size_type byte_count = object_size * count;
            void* address = ::operator new(byte_count);
            return reinterpret_cast<pointer> (address);
        }
    
        void deallocate(pointer p)
        {
            return ::operator delete(p);
        }
    
        void construct(pointer p, const_reference value)
        {
            ::new(p) T(value); //erstelle an position p das objekt T mit dem wert value
        }
    
        void destroy(pointer p)
        {
            p->~value_type();
        }
    };
    

    dabei fällt mir gerade auf, dass ich vergessen hatte, destroy in dem bsp aufzurufen...

    bb


Anmelden zum Antworten