SDL2 - Visual Studio 2017 SDL_FreeWAV Нарушение прав доступа - PullRequest
0 голосов
/ 18 сентября 2018

Я использую SDL2 и создал класс Audio для обработки игровой музыки и звуковых эффектов.Звук работает отлично, но всякий раз, когда класс Audio уничтожается, вызов SDL_FreeWAV() вызывает нарушение прав доступа:

Исключение, выданное в 0x000000006C7A8737 (SDL2.dll) в Program.exe: 0xC0000005:Место чтения нарушения доступа 0x00007FF4A9080008

Audio.h:

#pragma once

namespace Audio {

    class Audio {

    public:

        Audio ();
        Audio (char*, char*);
        ~Audio ();

        void pause (int);

    private:

        Uint32 wav_length;
        Uint8 *wav_buffer = NULL;
        SDL_AudioSpec wav_spec;
        SDL_AudioDeviceID device_id;
        int success;

    };

    class Music {

    public:

        Music ();
        Music (char*);
        ~Music ();

    private:

        Audio *audio = NULL;

    };

    class Effect {

    public:

        Effect ();
        Effect (char*);
        ~Effect ();

    private:



    };

};

Audio.cpp

#include "stdafx.h"
#include "Audio.h"

#include "SDL_audio.h"

namespace Audio {

    Audio::Audio () {

        //Default constructor

    }

    Audio::Audio (char *filename, char *channelName) {

        if (SDL_LoadWAV (filename, &this->wav_spec, &this->wav_buffer, &this->wav_length) == NULL) {

            std::cout << "[-] SDL: " << SDL_GetError () << "\n";

            exit (ERROR_SDL_AUDIO_WAV_LOAD);

        }

        this->device_id = SDL_OpenAudioDevice (channelName, 0, &this->wav_spec, NULL, 0);

        this->success = SDL_QueueAudio (this->device_id, this->wav_buffer, this->wav_length);

    }

    Audio::~Audio () {

        SDL_CloseAudioDevice (this->device_id);
        SDL_FreeWAV (this->wav_buffer); // <-- access violation here

    }

    void Audio::pause (int on) {

        SDL_PauseAudioDevice (this->device_id, on);

    }

};

1 Ответ

0 голосов
/ 18 сентября 2018

Пока у вас есть конструктор по умолчанию и вы не определили свой собственный, компилятор C ++ предоставляет вам move constructor и copy constructor бесплатно.Они копируют все элементы объекта.

Когда вы используете operator= (присвоение объекта другому объекту), он использует конструктор copy.Когда вы возвращаете временный объект (rvalue), он использует конструктор move.

К сожалению, конструкторы копирования и перемещения по умолчанию не подходят вам в этом случае.

Учтите это:

Audio a = Audio("filename", "channel");

В этой обманчиво простой строке кода вы:

  1. Создаете временный (rvalue) Audio объект
  2. Вызываете Audio::operator=
  3. Использование move constructor
  4. Удаление временного объекта

Итак, после этой строки действительного C ++, a имеет:

  1. device_id было закрыто.
  2. wav_buffer было освобождено.

Так, как мы можем это исправить?

Audio::Audio (char *filename, char *channelName) {
    if (SDL_LoadWAV (filename, &this->wav_spec, &this->wav_buffer, &this->wav_length) == NULL) {
        std::cout << "[-] SDL: " << SDL_GetError () << "\n";
        exit (ERROR_SDL_AUDIO_WAV_LOAD);
    }
    this->device_id = SDL_OpenAudioDevice (channelName, 0, &this->wav_spec, NULL, 0);
    this->success = SDL_QueueAudio (this->device_id, this->wav_buffer, this->wav_length);
}

Audio::Audio(Audio&& other) : // move constructor
    wav_length(other.wav_length),
    wav_buffer(other.wav_buffer),
    wav_spec(other.wav_spec),
    device_id(other.device_id),
    success(other.success)
{
    other.wav_buffer = nullptr;
}

Audio::~Audio () {
    if(wav_buffer != nullptr) {
        SDL_CloseAudioDevice (this->device_id);
        SDL_FreeWAV (this->wav_buffer); // Gives access violation
    }
}

Теперь, когдаAudio объект перемещен, его wav_buffer обнуляется, так что он не будет очищен при уничтожении.

...