Template-Funktion



  • Exakte aufgabenstellung:

    Implementieren Sie eine Template-Funktion

    template <typename TItor, typename TValue>
    void Shift(TItor begin, TItor end, size_t count, TValue val);

    die alle Elemente im über die Iteratoren begin und end
    gegebenen Bereich um count Stellen nach vorne verschiebt. Die letzten
    count Elemente sollen mit dem Wert val aufgefüllt werden. Es muss
    nicht geprüft werden, ob count größer als die Anzahl der Elemente ist
    . Achten Sie darauf, dass Ihr
    Algorithmus auch für Container mit sequentiellem Zugriff funktioniert, die Effizienz für Container
    mit wahlfreiem Zugriff aber darunter nicht leidet. Verwenden Sie zu diesem Zweck die Funktion std::advance(im Header) <iterator>

    Mein code:

    template <typename TItor, typename TValue>
    void Shift(TItor begin, TItor end, size_t count, TValue val){
    
    	TItor shiftit=begin;	
    	std::advance(shiftit, count);
    
    	std::copy(shiftit, end, begin);
    	std::fill(shiftit, end, val);
    
    }
    

    Wie mach ich hier die Fehlerbehandlung ohne das ich count überprüfe?


  • Mod

    Aussagekräftigeren Titel bitte.

    std::copy(shiftit, end, begin);
    std::fill(shiftit, end, val);
    

    solltest du noch einmal überdenken (Hinweis: copy hat einen Rückgabewert).

    Wie mach ich hier die Fehlerbehandlung ohne das ich count überprüfe?

    Welche ARt Fehler soll denn behandelt werden?



  • Implementieren Sie eine Template-Funktion

    Funktionstemplate.

    Statt TValue bitte typename std::iterator_traits<TItor>::value_type , und am Besten gleich eine const -Referenz.
    Und statt size_t einfach std::iterator_traits<TItor>::difference_type .

    Der Algo kann zu undefiniertem Verhalten führen, wenn count bspw. Null ist.
    Also ein

    if( count == 0 ) return;
    

    an den Anfang.
    Aber da kann noch mehr passieren.

    camper schrieb:

    std::copy(shiftit, end, begin);
    std::fill(shiftit, end, val);
    

    solltest du noch einmal überdenken (Hinweis: copy hat einen Rückgabewert).

    ➡

    shiftit = std::copy(shiftit, end, begin);
    


  • camper schrieb:

    Aussagekräftigeren Titel bitte.

    std::copy(shiftit, end, begin);
    std::fill(shiftit, end, val);
    

    solltest du noch einmal überdenken (Hinweis: copy hat einen Rückgabewert).

    der rückgabewert sollte gleich shiftit sein deshalb verwende ich hier die zuweisung nicht.

    Wie mach ich hier die Fehlerbehandlung ohne das ich count überprüfe?

    Welche ARt Fehler soll denn behandelt werden?

    Naja, das programm darf nicht abstürzen, aktuell stürzt es ja bei advanced ab, wenn count > als die größe des containers ist

    Sone schrieb:

    Implementieren Sie eine Template-Funktion

    Funktionstemplate.

    Statt TValue bitte typename std::iterator_traits<TItor>::value_type , und am Besten gleich eine const -Referenz.
    Und statt size_t einfach std::iterator_traits<TItor>::difference_type .

    Die Schnittstelle ist vorgegeben, da gibs also nichts zu rütteln

    Der Algo kann zu undefiniertem Verhalten führen, wenn count bspw. Null ist.
    Also ein

    if( count == 0 ) return;
    

    an den Anfang.
    Aber da kann noch mehr passieren.

    das wird in meinem testdriver überprüft
    grundproblem bleibt

    WIe verhindert man das advance() über den TItor end zugreift?



  • WIe verhindert man das advance() über den TItor end zugreift?

    Mach einfach eine assertion mit std::distance . Macht es zwar unperformant, aber ist ja nur im Debug-Modus.



  • Sone schrieb:

    Mach einfach eine assertion mit std::distance . Macht es zwar unperformant, aber ist ja nur im Debug-Modus.

    inwiefern soll das was bringen?
    distance gibt die diff zwischen ersten und letzten iterator zurück(difference_type)

    wie verhindert mir da ein assert den zugriff auf ein uninitialiserten speicherbereich?



  • Wenn die Bedingung von assert fehlschlägt ist nichts mehr mit weiterarbeiten. Programmende.



  • wrock schrieb:

    Implementieren Sie eine Template-Funktion

    template <typename TItor, typename TValue>
    void Shift(TItor begin, TItor end, size_t count, TValue val);

    die alle Elemente im über die Iteratoren begin und end
    gegebenen Bereich um count Stellen nach vorne verschiebt. Die letzten
    count Elemente sollen mit dem Wert val aufgefüllt werden. Es muss
    nicht geprüft werden, ob count größer als die Anzahl der Elemente ist
    . Achten Sie darauf, dass Ihr
    Algorithmus auch für Container mit sequentiellem Zugriff funktioniert, die Effizienz für Container
    mit wahlfreiem Zugriff aber darunter nicht leidet. Verwenden Sie zu diesem Zweck die Funktion std::advance(im Header) <iterator>

    Ich würde das jetzt dahingehend interpretieren:

    template<typename Iter, typename Val>
    void shift(Iter first, Iter last, std::size_t n, Val v){
      Iter i{first};
      std::advance(i, -n);
      std::fill(std::copy(first, last, i), last, v);
    }
    

    Evtl. bin ich ein wenig begriffsstutzig gerade, aber wenn "sequentieller Zugriff" meint ForwardIterator stehe ich mit meiner Interpretation etwas dumm da... 😞
    Wie komme ich auf die "linke Seite" eines ForwardIters ?

    Anyway: die Formulierung

    Es muss nicht geprüft werden, ob count größer als die Anzahl der Elemente ist

    interpretiere ich dahingehend, dass der Aufrufer prüfen muss, ob der Container "nach links hin" groß genug ist, dass es beim Auffüllen passt ergibt sich.

    So schön die Aufgabe auch klingt...da ist noch Interpretationsspielraum...



  • Vorsicht, std::size_t ist vorzeichenlos. -n macht nicht, was du erwartest.



  • Furble Wurble schrieb:

    ´
    Iter i{first};
    std::advance(i, -n);

    wie soll das funktionieren?

    du startest beim ersten und gehst nach "links"?
    da hast du doch schon beim ersten zugriff bereits einen fehler...

    testdriver:

    #include "template.h"
    #include <iostream>
    #include <vector>
    #include <list>
    #include <iterator>
    #include <algorithm>
    #include "genSort.h"
    
    int main(){	
    
    	std::vector<int> v1;
    	std::list<int> l1;
    	for(int i=0; i<20; i++){
    		v1.push_back(i);
    		l1.push_back(i);
    	}
    
    	std::cout << "v1: \n";
    	std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));
    	std::cout << "\nl1: \n";
    	std::copy(l1.begin(), l1.end(), std::ostream_iterator<int>(std::cout, " "));
    
    	Shift(v1.begin(), v1.end(), 15, 44);
    	Shift(l1.begin(), l1.end(), 5 , 22);
    
    	std::cout << "\nv1: \n";
    	std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));
    	std::cout << "\nl1: \n";
    	std::copy(l1.begin(), l1.end(), std::ostream_iterator<int>(std::cout, " "));
    
    	return 0;
    }
    

    Ausgabe:

    v1:
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
    l1:
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
    v1:
    15 16 17 18 19 5 6 7 8 9 10 11 12 13 14 44 44 44 44 44
    l1:
    5 6 7 8 9 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22

    wie gesagt, laut meiner interpretation ist das die aufgabenstellung

    problem liegt nach wie vor im exception handling

    Auszug aus cplusplus: http://www.cplusplus.com/reference/iterator/advance/

    Exception safety
    Throws if any of the arithmetical operations performed on the iterator throws, providing the same level of guarantee as such operations.

    hab das allerding snoch nicht "catchen" können..



  • kk seh grad das das gar net wirklich poasst/(testfälle)

    abe rwie gesagt
    exception handling,
    das andere bekomm ich schon hin


  • Mod

    template<typename Iter>
    void shift(Iter first, Iter last, typename std::iterator_traits<Iter>::difference_type n, const typename std::iterator_traits<Iter>::value_type& v){
      if ( n > 0 )
         std::fill( std::move( std::next( first, n ), last, first ), last, v );
      else if ( n < 0 )
         std::fill( begin, std::move_backward( first, std::next( last, n ), last ), v );
    }
    

    Wenn wir von Exception durch move/Zuweisung absehen, kann das nur fehlschlagen, wenn n zu groß ist, und genau dieser Fall muss laut Aufgabenstellung nicht geprüft werden. Ich sehe also nicht, welches Problem hier eigentlich diskutiert wird.



  • leider kein edit möglich...

    @sone hattest doch recht mit

    shiftit=std::copy(shiftit, end, begin);

    das behebt das problem



  • seldon schrieb:

    Vorsicht, std::size_t ist vorzeichenlos. -n macht nicht, was du erwartest.

    Haha...auch das noch! 🙂
    c++11 wirft std::prev() in den Ring.
    Oder - die Schnittstelle ist fragwürdig - mit Sones difference_type ginge es auch.

    Mir ist die Aufgabe nicht geheuer. 🙂

    @wrock
    ich müsste natürlich die Stelle, ab der Verschoben wird anpassen:

    shift(v1.begin()+18, v1.end(), 15, 44);  // ab der 18. Stelle 15 nach links
        auto it=l1.begin();
        std::advance(it,10);  // ab der 10. Stelle...
        shift(it, l1.end(), 5 , 22);  // ... 5 nach links
    

    Wie dem auch sei: meine Interpretation der Aufgabe ist auch gar nicht wichtig.

    Danke für Eure Aufmerksamkeit 🙂
    cu



  • camper schrieb:

    Wenn wir von Exception durch move/Zuweisung absehen, kann das nur fehlschlagen, wenn n zu groß ist, und genau dieser Fall muss laut Aufgabenstellung nicht geprüft werden. Ich sehe also nicht, welches Problem hier eigentlich diskutiert wird.

    Laut Aufgabenbesprechung soll das template aber trotzdem damit umgehen können falls dieser fall eintritt, aber eben nicht durch die überprüfung von count(n)

    Es muss nicht geprüft werden, ob count größer als die Anzahl der Elemente ist



  • [solved]

    template <typename TItor, typename TValue>
    void Shift(TItor begin, TItor end, size_t count, TValue val){
    
    TItor shiftit=begin;	
    
    for(size_t i =0; i<count; i++){
    
    	std::advance(shiftit, 1);
    	if(shiftit == end){
    		break;
    	}
    
    }
    
    shiftit=std::copy(shiftit, end, begin);
    std::fill(shiftit, end, val);
    
    }
    

  • Mod

    Das scheint mir für RandomAccessIteratoren ineffizient zu sein.



  • stimmt......




  • Mod

    Der Fall begin == end wird auch nicht richtig behandelt, das ist allerdings trivial korrigierbar.


Anmelden zum Antworten