Search code examples
c++staticstdvector

Why this function variable only works if it's static?


I'm trying to put a bunch of sounds in a std::vector because it's very convenient.

I'm using an auxiliary variable called laser, load the sound into it and, if it's everything ok, push_back into the vector. When I try to play any the sound, nothing happens, not even error messages which should be printed if anything goes wrong.

Just for curiosity I made laser static and voilá, it works flawlessly (or it seems to).

I'd like to know why.

Header file:

// audio_system.h
#ifndef KUGE_HEADERS_AUDIO_SYSTEM_H_
#define KUGE_HEADERS_AUDIO_SYSTEM_H_

#include "event.h"
#include "system.h"
#include "../sdl2_wrappers/sdl2_wrappers.h"
#include "../include/resources_path.h"
#include <vector>

namespace kuge {

class AudioSystem : virtual public System {
 public:
  AudioSystem(EventBus& bus): System(bus) {}
  void handleEvent(const Event& event);
  static bool loadResources();

 private:
  static void generateRandomSequence();
  
  static std::vector<ktp::SDL2_Sound> lasers_;
};

} // end namespace kuge

#endif // KUGE_HEADERS_AUDIO_SYSTEM_H_

cpp file:

#include "event_bus.h"
#include "audio_system.h"

std::vector<ktp::SDL2_Sound> kuge::AudioSystem::lasers_{};

void kuge::AudioSystem::generateRandomSequence() {}

void kuge::AudioSystem::handleEvent(const Event& event) {
  switch (event.getType()) {
    case EventTypes::LaserFired:
      if (lasers_[0].play() == -1) {
        ktp::logSDLError("laser_.play");
      }
      break;
    
    default:
      break;
  }
}

bool kuge::AudioSystem::loadResources() {
  static ktp::SDL2_Sound laser{};            // here! If I don't make this static, nothing happens
  if (!laser.loadSound(ktp::getResourcesPath() + "sounds/laser2.wav")) {
    return false;
  } else {
    lasers_.push_back(laser);
  }
  ktp::logMessage("AudioSystem: resources loaded.");
  return true;
}

Solution

  • OK, so following the advices from the comments, I've made the following changes to make ktp::SDL2_Sound class follow the rule of 0 and now it works without the need to set the laser variable to static. This solves the problem, but I'm still not sure why it worked being static.

    class SDL2_Sound {
     public:
      //~SDL2_Sound() { free(); }       // now I don't need any destructor
      
      bool loadSound(const std::string& path);
      int play(int loops = 0);
    
     private:
      void free();
      // Mix_Chunk* sound_ = nullptr;   // old raw pointer
      std::shared_ptr<Mix_Chunk> sound_{};
    };
    
    
    /* void ktp::SDL2_Sound::free() {   
      if (sound_ != nullptr) {
        Mix_FreeChunk(sound_);
        sound_ = nullptr;
      }
    } */
    
    bool ktp::SDL2_Sound::loadSound(const std::string& path) {
      //free();
      sound_.reset(Mix_LoadWAV(path.c_str()), &Mix_FreeChunk);
      //sound_ = Mix_LoadWAV(path.c_str());
      if (sound_ == nullptr) {
        ktp::logSDLError("Mix_LoadWAV", path);
        return false;
      }
      return true;
    }