'operator new': Funktion akzeptiert keine 2 Argumente



  • Das Wichtigste vom Code:

    template <class T>
    class vector
    
    ...
    
    vector(const T *arr, uint count)
    	: m_ptr(reinterpret_cast<T*>(new char[count * sizeof(T)])) //T *m_ptr
    	, m_used(count) //uint, Anzahl der benutzten Elemente
    	, m_constructed(count) //uint, Anzahl der konstruierten Elemente
    	, m_allocated(count) //uint, Anzahl der Elemente, für die m_ptr Platz hat
    {
    	for (uint i = 0; i < size(); ++i) //size() gibt m_used zurück
    	{
    		new (data() + i) T(arr[i]); //data() gibt m_ptr zurück
    //C2660: 'operator new': Funktion akzeptiert keine 2 Argumente
    	}
    }
    
    template <class T>
    class basic_string
    {
    //...
    
    	basic_string(const T *str)
    		: m_content(str, xstrlen(str) + 1)
    	{
    	}
    
    //...
    
    private:
    
    	vector<T> m_content;
    };
    
    typedef basic_string<char> string;
    
    string getSth()
    {
    	char buf[256];
    	...
    	return buf; //hier gibts das obige Problem, sonst nicht
    }
    

    Compiler: VC++ 08
    Woran liegt das?



  • was willst du mit der Zeile erreichen? Das hast vergessen dazuzuschreiben 😉



  • pumuckl schrieb:

    was willst du mit der Zeile erreichen? Das hast vergessen dazuzuschreiben 😉

    Es ist doch offensichtlich, dass der Speicher, auf den 'm_ptr' zeigt, mit 'T's gefüllt werden soll. Und zwar Kopien der Elemente vom Parameter 'arr'.



  • Hast Du auch den Header <new> vorher eingebunden?



  • Sebastian Pizer schrieb:

    Hast Du auch den Header <new> vorher eingebunden?

    Danke, das war das Problem. Ich wusste nicht, dass man für ein so grundlegendes Feature einen Header braucht.


  • Mod

    Richtig richtig wird es, wenn das placement-Argument nach void* gecasted wird; andernfalls ist es denkbar, dass eine andere Überladung gewählt wird.



  • TyRoXx schrieb:

    : m_ptr(reinterpret_cast<T*>(new char[count * sizeof(T)]))
    

    Warum reinterpret_cast und der Umweg über char[] ? Machs doch so:

    : m_ptr(static_cast<T*>(operator new(count * sizeof(T))))
    

    Wobei ich eher empfehle, für sowas eine Funktion zu schreiben:

    T* allocate(size_t count)
    {
        return static_cast<T*>(operator new(count * sizeof(T)));
    }
    
    : m_ptr(allocate<T>(count))
    


  • Du weist doch genau, wieso^^
    Beim Vektor/vector find ich das auch sinnvoll - es muss nicht zwangsläufig nen standard-konstruktor geben und vor allem will ich nicht, dass er mir unkontrolliert viele objekte erstellt, von denen ich gar nichts weiß...
    beim string wiederrum ists egal.

    bb



  • Nexus schrieb:

    TyRoXx schrieb:

    : m_ptr(reinterpret_cast<T*>(new char[count * sizeof(T)]))
    

    Warum reinterpret_cast und der Umweg über char[] ? Machs doch so:

    : m_ptr(static_cast<T*>(operator new(count * sizeof(T))))
    

    Wobei ich eher empfehle, für sowas eine Funktion zu schreiben:

    T* allocate(size_t count)
    {
        return static_cast<T*>(operator new(count * sizeof(T)));
    }
    
    : m_ptr(allocate<T>(count))
    

    reinterpret_cast , weil static_cast nicht ausreicht, um Zeiger zu konvertieren (error C2440).
    Zum Freigeben des Speichers nimmt man dann operator delete[](void*) oder wie?



  • Jopp...
    aber statt new char[] nimmt man eigtl operator new[] :

    template<typename T>
    void foo(size_type size)
    {
      void *memory_block = operator new[size * sizeof(T)];
    
      size_type i = size_type();
      try
      {
        for(; i != size; ++i)
        {
          new(memory_block + i*sizeof(T)) T();
        }
      }
      catch(...)
      {
        for(; i != 0; ++i)
        {
          reinterpret_cast<T*>(memory_block + (i-1)*sizeof(T))->~T();
        }
        throw;
      }
    
      //mach was...
    
      for(size_type i = size_type(); i != size; ++i)
      {
        reinterpret_cast<T*>(memory_block + i*sizeof(T))->~T();
      }
      operator delete[] memory_block;
    }
    

    ist ziemlich hässlich, aber sollte die vorgehensweise verdeutlichen^^
    das ganze macht man aber normalerweise über nen allocator...

    bb



  • TyRoXx schrieb:

    reinterpret_cast , weil static_cast nicht ausreicht, um Zeiger zu konvertieren (error C2440).

    Er reicht schon aus, allerdings nur von void* zu T* und umgekehrt oder in Klassenhierarchien.

    TyRoXx schrieb:

    Zum Freigeben des Speichers nimmt man dann operator delete(void*) oder wie?

    Ja, genau. Aber vorher nicht vergessen, den Destruktor über ptr->~T() aufzurufen.



  • unskilled schrieb:

    aber statt new char[] nimmt man eigtl operator new[] :

    template<typename T>
    void foo(size_type size)
    {
      void *memory_block = operator new[size * sizeof(T)];
    

    Das sieht aber komisch aus. Ich programmiere nicht so oft std::vector nach, deswegen bin ich bei diesem operator new-Kram nicht so fit. Aber ich würde raten, dass das wenn überhaupt ::operator new[](size * sizeof(T)); heißen müsste. void* finde ich in diesem Fall recht unpraktisch.

    size_type i = size_type();
    

    Hmm.. hätte einfach =0; geschrieben. Man muss das ja nicht alles so kompliziert machen. :p

    try
      {
        for(; i != size; ++i)
        {
          new(memory_block + i*sizeof(T)) T();
    

    Zeigerarithmetik auf void* ?

    }
      }
      catch(...)
      {
        for(; i != 0; ++i)
        {
          reinterpret_cast<T*>(memory_block + (i-1)*sizeof(T))->~T();
    

    Zeigerarithmetik auf void* ?
    Außerdem: Es müsste --i in der Schleife sein, nicht?

    operator delete[] memory_block;
    

    sieht auch komisch aus. Fehlen da nicht die Klammern um memory_block ?

    Gruß,
    SP



  • Japp - da waren ziemlich viele Fehler drin - ist eben schon ne ganze Zeit her und ich dachte, ich bekomms noch so ausm Stehgreif hin :S

    so sollte es stimmen:
    (und sieht auch schon um einiges besser aus ;o))

    #include <new>
    
    typedef std::size_t size_type;
    
    template<typename T> 
    void foo(size_type size) 
    { 
      T *memory_block = static_cast<T*>( ::operator new(size * sizeof(T)) ); 
    
      size_type i = size_type(); 
      try 
      { 
        for(; i != size; ++i) 
        { 
          new(memory_block + i) T(); 
        } 
      } 
      catch(...) 
      { 
        for(; i != 0; --i)
        { 
          memory_block[i].~T();
        } 
        throw; 
      } 
    
      //mach was... 
    
      for(size_type i = size_type(); i != size; ++i) 
      { 
        memory_block[i].~T(); 
      } 
      ::operator delete ( static_cast<void*>(memory_block) );
    }
    
    int main()
    {
    	foo<int>(45678);
    }
    

    hätte einfach =0; geschrieben. Man muss das ja nicht alles so kompliziert machen.

    kA, ich bin da immer bissl warning-paranoid^^ vll gibts ja auch irgendwo mal nen so eigenartigen size_type, bei dem irgend nen compiler unnötigerweise ne warning von sich gibt, wenn man ihm nen int zuweist...
    und unübersichtlicher find ich es auch nicht...

    bb



  • unskilled schrieb:

    catch(...) 
      { 
        for(; i != 0; --i)
        { 
          memory_block[i].~T();
        } 
        throw; 
      }
    

    <räusper>Ähäm</räusper>

    while (i>0) memory_block[--i].~T();
    

    😃



  • geschmackssache? 😛



  • Wenn, dann

    while(i > 0)
       memory_block[i--].~T();
    


  • Oder man schreibt sich vernünftige Funktionen für sowas.

    destroy_range(memory_block, memory_block+size);
    

    🕶



  • doch nix mit geschmackssache xD
    hast recht, da ist nen fehler drin...

    for(; i != 0; --i) 
        { 
          memory_block[i-1].~T(); 
        }
    

    oder deine(SP) Lösung...

    das i-te Element dort wurde ja noch nicht erstellt -> kann nicht freigegeben werden... bäm! 😉

    bb



  • wx++ schrieb:

    Wenn, dann

    while(i > 0)
       memory_block[i--].~T();
    

    Nein, das eben nicht! Mir ging's nicht um for<->while sondern genau um die Indizes.



  • Ja, du hast Recht.
    Ich hab's einfach blind von seinem Code übernommen.


Log in to reply