c++ vectors and a directx audio class

Started by
4 comments, last by moucard 19 years, 10 months ago
Hi to everyone! I need your help with this because my knowledge of vectors seems to get smaller and smaller everyday (the more I learn the less I know). I have a class that initializes directx sound objects like this:

//header
#ifndef _CSOUND_H
#define _CSOUND_H

#include "CAudio.h"

class CSound {
private:
	IDirectMusicPerformance8*	m_pPerformance;
	IDirectMusicLoader8*		m_pLoader;
	IDirectMusicSegment8*		m_pSegment;
public:
	CSound(char* szFilename_, IDirectMusicPerformance8 *pPerformance,
		IDirectMusicLoader8 *pLoader);
	~CSound();

	void Play();
	void Stop();

	void SetRepeats(DWORD);
	bool IsPlaying();
};

#endif

//.cpp
#include "CSound.h"

CSound::CSound(char *szFilename_, IDirectMusicPerformance8 *pPerformance,
		IDirectMusicLoader8 *pLoader)
{
	WCHAR wszFile[MAX_PATH];

	m_pSegment = NULL;
	m_pPerformance = pPerformance;
	m_pLoader = pLoader;

	//Create segment
	CoCreateInstance(CLSID_DirectMusicSegment, NULL, CLSCTX_INPROC, IID_IDirectMusicSegment8, 
		(void**)&m_pSegment);

	//Load segment from file
	MultiByteToWideChar(CP_ACP, 0, szFilename_, -1, wszFile, MAX_PATH);

	if (FAILED(m_pLoader->LoadObjectFromFile(CLSID_DirectMusicSegment, IID_IDirectMusicSegment8, wszFile,
		(void**)&m_pSegment))) {
		MessageBox(NULL, "Failed to load sound", "CSound", MB_OK | MB_ICONEXCLAMATION);
	}

	//Download band
	m_pSegment->Download(m_pPerformance);
}

CSound::~CSound()
{
	if (m_pSegment) {
		m_pSegment->Unload(m_pPerformance);
		m_pSegment->Release();
		m_pSegment = NULL;
	}
}

void CSound:lay()
{
	m_pPerformance->PlaySegmentEx(m_pSegment, 0, NULL, 
		DMUS_SEGF_SECONDARY, 0, 0, NULL, NULL);
}

void CSound::Stop()
{
	m_pPerformance->StopEx(m_pSegment,0,0);
}

void CSound::SetRepeats(DWORD dwRepeats)
{
	//A value of DMUS_SEG_REPEAT_INFINITE means infinite
	m_pSegment->SetRepeats(dwRepeats);
}

bool CSound::IsPlaying()
{
	return (m_pPerformance->IsPlaying(m_pSegment, NULL) == S_OK);
}
 
The code is based from this http://www.riaz.de/tutorials/dxaudio02/dxaudio02.html site. I''ve tested the code creating a normal istance of my class and it all works fine. (Using Win2K and VC++ 6.0) But what I would like to do is push the sound object instances in a vector container. Currently I "do" it like this:

m_cAudio = new CAudio(GetHWND());
m_cAudio->SetMasterVolume(500);

m_cSounds.push_back(CSound("perdu.wav",
  m_cAudio->GetPerformance(), 
  m_cAudio->GetLoader()));

m_cSounds.push_back(CSound("gagne.wav",
  m_cAudio->GetPerformance(), 
  m_cAudio->GetLoader()));
 
The problem is that it doesn''t work. (using the same method to fill a vector using another class I''ve created works just fine). If I''ve understood correctly the object is created and then destroyed. (Using a breakpoint, I see that the destructor is called at the "push_back".) So it actually closes down the channel before I get to use it (leading to exceptions and such). What do you propose I should do? Move the destructor stuff to another function? Is there another way to do it properly? Thank you for your time!
Advertisement
Hello, STL on VC6 is messed up, you can get service packs that will fix alot of bugs, download SP6.

You haven't shown us how you've declared your variable m_cSounds, i assume its of type:
std::vector<CSound>


if you want a vector of "T" then the type "T" has the requirement of being assignable "=", at the moment you haven't defined an assignment operator your self so a default one is provideded that just assigns all the old memebers to the new members of the object created when you call push_back, so its basically copying all thous directx member pointers not sure thats what you wont.

You could either define an appropriate assignement operator or store pointers to CSound objects but then you have to manage the memory yourself if you create the objects on the heap.

[edited by - snk_kid on June 2, 2004 12:32:56 PM]
you need to write an assignment operator, a copy constructor and a destructor for your class. You''ve probably got one of these already (a destructor) but the rule is that if you''ve got one you probably need all three (Rule of Three).

You''ll be making copies of the object by inserting it into the vector, the pointer to the resource will be copied (rather than creating a new resource), but the temporary object will call the destructor and delete the resource. Bang.

2 options are:
1) Use smart pointers for the resources
2) Store pointers to objects in the vector rather than the objects themselves.
Thanks for the answers guys, they were really illuminating.
I've bypassed the problem with using another method for the desrtuction of the directx objects. So when I'm finished with it I use:
for (int i = 0; i < m_cSounds.size(); i++) {	m_cSounds.CloseDown();}m_cSounds.clear();   

Do you think that I'm having a memory leak with the above method?
I guess that since the m_cSounds contained in the vector point to the same memory and since I'm closing them down, I don't. But I'm not a 100% sure.
Since my educcation for the containers is still poor I had no idea I had to provide a = operator and a copy constructor.
Also for the creation of the vector, yes I use
vector CSound m_cSounds; <--- I had trouble with the >< characters
Thank you again for your answers.

[edited by - moucard on June 2, 2004 12:56:45 PM]

[edited by - moucard on June 2, 2004 12:57:48 PM]
if closeDown is the same as the deconstructor and you only need to release resources when your finished with the object then i would leave out the closeDown unless you wont to release resources at any time but still use the same oject.

If you wont to have container of objects then you''ll have to define those three methods we mentioned like so:
#include "CAudio.h"#include <string>class Sound {	IDirectMusicPerformance8*	m_pPerformance;	IDirectMusicLoader8*		m_pLoader;	IDirectMusicSegment8*		m_pSegment;public:        Sound(const Sound&); //copy constructor        Sound& operator=(const Sound&); //assignement operator        ~Sound();	Sound(const std::string& filename,               IDirectMusicPerformance8 *pPerformance,		       IDirectMusicLoader8 *pLoader);		void play() const;	void stop() const;	void set_repeats(int);	const bool is_playing() const;};


But i don''t think there is an appropriate way to copy and assign unless you don''t mind copying & assigning directx pointers around. I think you will be better of with a container of pointers to Sound, then everytime you call push_back it will just create a new pointer to Sound and assign the pointer passed to push_back to it, when your finished with it just remember to delete the objects on the heap so you don''t get memory leaks.
Just to illustrate what i mean't:

#include "CSound.h"#include <algorithm>#include <functional>#include <vector>template<class T>struct deleter : public std::unary_function< T&, void > {public:    void operator()(T& obj) const {	if(obj != 0) {            delete obj;	    obj = 0;	}		     }};int main() {   std::vector<CSound*> my_sounds();   //... do some stuff   my_sounds.push_back(new CSound());   my_sounds.push_back(new Csound());   //... do some more stuff  std::for_each(my_sounds.begin(),                 my_sounds.end(),                deleter<CSound*>());  my_sounds.clear();  return 0;}


[edited by - snk_kid on June 2, 2004 1:58:11 PM]

This topic is closed to new replies.

Advertisement