QueryPerformanceFrequency Zugriffsverletzung



  • unskilled schrieb:

    Nein, getter und setter zu sparen, nur weil man sich die 3-5zeilen code sparen möchte, sollte nie eine option sein.

    Genau. Nur wenn man dann beim setter ohne Tests auf Korrektheit des neuen Werts (was auch nicht immer notwendig ist) den neuen Wert setzt, kann man das Attribut auch gleich public machen. Andererseits können später so auch keine evtl. notwendig gewordenen Test eingebaut werden, weshalb es wirklich geschickter ist, in unsicheren Fällen tatsächlich gleich den primitiven setter anzubieten.



  • Der Verzicht auf eine Setter Methode führt aber nicht zu einer Zugriffsverletzung.
    Was dein Problem ist kann ich jetzt spontan auch nicht sagen, du hast etwas wirr durcheinander geredet. Am besten mal ein vollständiges Beispiel posten.



  • Wie das an sich funktioniert:

    LARGE_INTEGER counter;
    BOOL result = QueryPerformanceCounter(&counter);
    
    if(result == FALSE)
      throw std::runtime_error("...");
    
    LONGLONG ticks = counter.QuadPart;
    std::cout << ticks << std::endl;
    

    nichts da mit cast.

    steht aber auch in der msdn genau so als bsp., wenn ich mich nicht täusche...

    bb



  • Also so funktioniert es auch: (solange frequency private ist)

    if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(timer->getFrequencyPointer()))) {
    

    wobei getFrequencyPointer so aussieht:

    long long *timers::getFrequencyPointer() {
    	return &frequency;
    };
    

    Das Beispiel von unskilled funktioniert aber auch wunderbar.
    Also soll ich es jetzt wie unskilled machen oder mit cast?

    Was mir jetzt aber Kopfzerbrechen bereitet ist der setter:

    void timers::setFrequency(long long var) {
    	frequency = var;
    };
    

    So wird es in jedem Tutorial und Buch beschrieben, so habe ich es auch schon oft gemacht, aber der Debugger spuckt hier wieder eine Zugriffsverletzung aus.
    Irgendwie verwirrt mich hier C++ ein bisschen.

    PS:

    Unskilled schrieb:

    class und struct sind in C++ (bis auf den default-zugriff) identisch

    Ich weiß, aber ich habe bei struct noch nie einen Konstruktor oder ein getter oder setter gesehen.



  • Du solltest definitiv auf die casts verzichten und es lieber so machen, wie es gedacht ist...

    Allg. verstehe ich nicht, wieso du eine Frequenz ändern möchtest.
    Die ist über QueryPerformanceFrequency zu erfragen. Verwendung auch hier wie oben beschrieben(á la QuadPart)

    Wie wäre es denn, wenn du endlich mal verraten würdest, was du wirklich möchtest.
    Dann könnte man dir auch sagen, ob hier der Setter oder die public-Variable besser/intuitiver wäre.
    Außerdem habe ich die Vermutung, dass das alles nicht so recht zusammenpasst, was du machen möchtest... ^^

    bb

    PS: structs ohne CTor sind eher die Ausnahme in C++ ;o)



  • Was ich vorhabe ist das hier:

    void TimerInit(void) {										// Initialisiere unseren Timer (bereite ihn vor)
    	memset(&timer, 0, sizeof(timer));						// lösche unsere Timer Struktur
    	// überprüfe, ob ein Performance Counter verfügbar ist
    	// wenn einer verfügbar ist, wird die Timer Frequenz aktualisiert
    	if (!QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(timer->getFrequencyPointer()))) {
    		// Kein Performace Counter verfügbar
    		timer->setFrequency(1000);
    		timer->performance_timer = false;					// Setze Performance Timer auf FALSE
    		timer->mm_timer_start = timeGetTime();				// benutze timeGetTime() um die aktuelle Zeit zu ermitteln
    		timer->resolution = 1.0f/1000.0f;					// Setze unsere Timer Auflösung auf .001f
    		//timer->frequency = 1000;							// Setze unsere Timer Frequenz auf 1000
    		timer->mm_timer_elapsed = timer->mm_timer_start;	// Setze die verstrichene Zeit gleich der aktuellen Zeit
    	} else {
    		// Performance Counter ist verfügbar, benutze diesen statt des Multimedia Timers
    		// ermittle die aktuelle Zeit und speichere sie in performance_timer_start
    		QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&timer->performance_timer_start));
    		timer->performance_timer = true;					// Setze Performance Timer auf TRUE
    		// berechne die Timer Auflösung mittels der Timer Frequenz
    		timer->resolution = static_cast<float>((static_cast<double>(1.0f))/(static_cast<double>(timer->frequency)));
    		// Setze die vergangene Zeit gleich der aktuellen Zeit
    		timer->performance_timer_elapsed = timer->performance_timer_start;
    	} 
    }
    

    Die Klasse sieht momentan so aus:

    class timers {
    public:
    	timers();
    	~timers();
    	//long long frequency;				// Timer Frequenz
    	float resolution;					// Timer Auflösung
    	unsigned long mm_timer_start;		// Multimedia Timer Start Wert
    	unsigned long mm_timer_elapsed;		// Multimedia Timer verstrichene Zeit
    	bool performance_timer;				// wird der Performance Timer benutzt?
    	long long performance_timer_start;	// Performance Timer Start Wert
    	long long performance_timer_elapsed;// Performance Timer verstrichene Zeit
    	long long getFrequency(void);
    	long long *getFrequencyPointer(void);
    	void setFrequency(long long var);
    private:
    	long long frequency;
    };
    

    Die Public Variablen, können bei mir nicht besser sein, da die alle eine Zugriffsverletzung ausspucken (der setter aber auch).
    Momentan bleibe ich immer an der ersten Zeile nach der QueryPerfomanceFrequency hängen, dass heißt ich komme nicht mal bis zum else Zweig.
    Das Problem wäre meiner Meinung eigentlich schon gelöst, wenn der setter funktionieren würde.



  • Deine Zugriffsverletzung kommt wohl da

    memset(&timer, 0, sizeof(timer));
    

    her.
    Verwende doch einen Konstruktor, wenn du eh schon C++ programmierst...
    Wie ist btw. timer deklariert?



  • Danke, da lag der Fehler. Jetzt funktioniert alles einwandfrei. Aber wieso gibt es eine Zugriffsverletzung, wenn ich alles auf 0 setze.
    Bei Pointern übergebe ich dann einen NULL-Pointer, das ist mir klar.
    Aber timer->frequency ist ja kein Pointer, und trotzdem gibt es da eine Zugriffsverletzung. Das ist mir noch nicht ganz klar.



  • timer selbst ist offenbar ein Pointer (sonst würdest du ja mit timer.frequency darauf zugreifen). Mit deinem memset setzt du somit timer auf NULL .



  • Hmm.. Du möchtest also einen Timer, der den performance-timer verwendet, wenn der verfügbar ist und wenn nicht, einen normalen Timer?
    Und du möchtest Informationen über die Frequenz und Auflösung (neben der vergangenen Zeit) bereitstellen?

    bb



  • Ja das möchte ich, und es funktioniert jetzt auch 🙂

    ipsec schrieb:

    timer selbst ist offenbar ein Pointer (sonst würdest du ja mit timer.frequency darauf zugreifen). Mit deinem memset setzt du somit timer auf NULL .

    Ja timer ist auch ein Pointer, habe ich ganz vergessen. Naja ich werde jetzt noch ein paar Übungen zu Pointern machen, da ich irgendwie das Gefühl habe, ich bin noch nicht ganz dahinter gekommen.



  • was spricht dann gegen so etwas in der richtung:

    strcut timer
    {
      typedef LOGNLONG tick_type;
      typedef float second_type;
    
      timer()
      {
        restart();
      }
    
      void restart()
      {
        start = get_ticks();
      }
    
      tick_type get_elapsed() const
      {
        tick_type stop = get_ticks();
        return stop - start;
      }
    
      tick_type get_ticks_per_second() const
      {
        ;
      }
    
      static second_type get_seconds_from_ticks(tick_type ticks, tick_type ticks_per_second)
      {
        return second_type(ticks)/second_type(ticks_per_second);
      }
    private:
      tick_type start;
    
      tick_type get_ticks() const
      {
        LARGE_INTEGER ret_val;
        BOOL successfull = QueryPerformanceCounter(&ret_val);
        if(successfull == FALSE)
        {
          /*backup methode wählen oder einfach exception werfen*/;
        }
        return ret_val.QuadPart;
      }
    };
    
    int main()
    {
      timer t;
      /*...*/
      timer::second_type elapsed = timer::get_seconds(t.get_elapsed(), t.get_seconds_per_tick());
      std::cout << elapsed << std::endl;
    }
    

    ist sehr lückenhaft, aber sollte doch ein wenig übersichtlicher sein 😉

    Ich weiß nicht, wozu die Backup-Methode brauchst, aber ohne die würde es noch mal ein ganzes Stück übersichtlicher werden...^^
    Ich kann mir gerade nicht vorstellen, was passieren soll, dass dort nen Fehler auftritt - aber wenn, dann kann er auch in der get_elapsed fkt. auftauchen - und dann? dann hat man nämlich keine alternativ start-zeit, sondern nur die, die man dann wegwerfen kann...
    also gleich beide speichern - und beide Methoden zum stoppen anbieten?
    Das die Timer-Auflösung hier stimmt, sollte dich nicht veranlassen, das immer so zu berechnen!? Andere Methoden geben auch Millisekunden wieder, aber haben nur eine Auflösung von um die 16ms ( GetTickCount() ) z.Bsp.

    bb


Anmelden zum Antworten