简体   繁体   English

SDL2-Visual Studio 2017 SDL_FreeWAV访问冲突

[英]SDL2 - Visual Studio 2017 SDL_FreeWAV Access Violation

I'm using SDL2, and created an Audio class to handle game music and sound effects. 我正在使用SDL2,并创建了一个Audio类来处理游戏音乐和声音效果。 The sound works perfectly, but whenever the Audio class is destructed, the SDL_FreeWAV() call throws an access violation: 声音效果完美,但是只要销毁Audio类, SDL_FreeWAV()调用就会引发访问冲突:

Exception thrown at 0x000000006C7A8737 (SDL2.dll) in Program.exe: 0xC0000005: Access violation reading location 0x00007FF4A9080008 在Program.exe中的0x000000006C7A8737(SDL2.dll)处引发异常:0xC0000005:访问冲突读取位置0x00007FF4A9080008

Audio.h: 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 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);

    }

};

As long as you have a default constructor and didn't define your own, the C++ compiler gives you a move constructor and a copy constructor for free. 只要您具有默认构造函数且未定义自己的构造函数,C ++编译器就会为您免费提供move constructorcopy constructor They shallow-copy all members of the object. 他们浅拷贝对象的所有成员。

When you use operator= (assignment of the object to another object), it uses the copy constructor. 当您使用operator= (将对象分配给另一个对象)时,它将使用copy构造函数。 When you return a temporary object (rvalue), it uses the move constructor. 当您返回一个临时对象(右值)时,它将使用move构造函数。

Sadly the default copy and move constructors don't fit you in this case. 遗憾的是,在这种情况下,默认的复制和移动构造函数不适合您。

Consider this: 考虑一下:

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

In this deceptively simple line of code you're: 在这看似简单的代码行中,您是:

  1. Making a temporary (rvalue) Audio object 制作一个临时(右值) Audio对象
  2. Calling Audio::operator= 呼叫Audio::operator=
  3. Using the move constructor 使用move constructor
  4. Deleting the temporary object 删除临时对象

So after this line of valid C++, a has: 因此,在这行有效的C ++之后, a具有:

  1. device_id that was closed. 已关闭的device_id
  2. wav_buffer that was freed. 已释放的wav_buffer

So how do we fix this? 那么我们该如何解决呢?

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
    }
}

Now when an Audio object is moved, its wav_buffer is nullified so that it won't be cleaned up when it's destroyed. 现在,当移动Audio对象时,其wav_buffer会无效,以便销毁它时不会对其进行清理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM