Пока у вас есть конструктор по умолчанию и вы не определили свой собственный, компилятор C ++ предоставляет вам move constructor
и copy constructor
бесплатно.Они копируют все элементы объекта.
Когда вы используете operator=
(присвоение объекта другому объекту), он использует конструктор copy
.Когда вы возвращаете временный объект (rvalue), он использует конструктор move
.
К сожалению, конструкторы копирования и перемещения по умолчанию не подходят вам в этом случае.
Учтите это:
Audio a = Audio("filename", "channel");
В этой обманчиво простой строке кода вы:
- Создаете временный (rvalue)
Audio
объект - Вызываете
Audio::operator=
- Использование
move constructor
- Удаление временного объекта
Итак, после этой строки действительного C ++, a
имеет:
device_id
было закрыто. 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
обнуляется, так что он не будет очищен при уничтожении.