SFML, sf::Music cannot be copied

Started by
12 comments, last by alvaro 11 years, 7 months ago
Hello.
I am currently trying to load sf::Music intro my std::vector via this
I try to use vectors push_back() function.
I get 'ALLOT' of errors that basically say i cant copy sf::Music /*"Error report at bottom"*/

How do i store sf::Music intro a std::vector?

Is there avoid using memory allocation? like

std::vector <sf::Music*> MusicList;
MusicList[0] = new sf::Music;



void Music::InitMusic(App& obj_App)
{
std::ifstream IStream("./Data/Music.txt");
if(IStream.is_open())
{
int HowManyMusic;
IStream >> HowManyMusic;
IStream.ignore(2);
for(int i = 0; i < HowManyMusic; i++)
{
std::string FilePath;
IStream >> FilePath;
IStream.ignore(2);
sf::Music tempMusic;
if(!tempMusic.openFromFile(FilePath))
{
obj_App.obj_ErrorHandle.PrintError("'" + FilePath + " File Could not be opened");
}
MusicList.push_back(tempMusic); /* Error occurs here */
}
}
else
{
obj_App.obj_ErrorHandle.PrintError("'./Data/Music.txt' File Could not be opened");
}
}


Error report


..\Libraries\SFML-2.0-rc\include\SFML\System\Thread.hpp|49|instantiated from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = sf::Music]'|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_vector.h|737|instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
C:\c++ Project\One day\Music.cpp|32|instantiated from here|
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp|67|error: 'sf::NonCopyable::NonCopyable(const sf::NonCopyable&)' is private|
..\Libraries\SFML-2.0-rc\include\SFML\System\Thread.hpp|49|error: within this context|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\SoundStream.hpp|45|note: synthesized method 'sf::Thread::Thread(const sf::Thread&)' first required here |
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp|53|note: synthesized method 'sf::SoundStream::SoundStream(const sf::SoundStream&)' first required here |
..\Libraries\SFML-2.0-rc\include\SFML\System\Mutex.hpp|48|instantiated from 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = sf::Music]'|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_vector.h|737|instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
C:\c++ Project\One day\Music.cpp|32|instantiated from here|
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp|67|error: 'sf::NonCopyable::NonCopyable(const sf::NonCopyable&)' is private|
..\Libraries\SFML-2.0-rc\include\SFML\System\Mutex.hpp|48|error: within this context|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp|53|note: synthesized method 'sf::Mutex::Mutex(const sf::Mutex&)' first required here |
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ext\new_allocator.h||In member function 'void __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = sf::Music]':|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\ext\new_allocator.h|105|note: synthesized method 'sf::Music::Music(const sf::Music&)' first required here |
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp||In member function 'sf::Thread& sf::Thread::operator=(const sf::Thread&)':|
..\Libraries\SFML-2.0-rc\include\SFML\System\Thread.hpp|49|instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_vector.h|741|instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
C:\c++ Project\One day\Music.cpp|32|instantiated from here|
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp|79|error: 'sf::NonCopyable& sf::NonCopyable::operator=(const sf::NonCopyable&)' is private|
..\Libraries\SFML-2.0-rc\include\SFML\System\Thread.hpp|49|error: within this context|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\SoundStream.hpp||In member function 'sf::SoundStream& sf::SoundStream::operator=(const sf::SoundStream&)':|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\SoundStream.hpp|45|note: synthesized method 'sf::Thread& sf::Thread::operator=(const sf::Thread&)' first required here |
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp||In member function 'sf::Music& sf::Music::operator=(const sf::Music&)':|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp|53|note: synthesized method 'sf::SoundStream& sf::SoundStream::operator=(const sf::SoundStream&)' first required here |
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp||In member function 'sf::Mutex& sf::Mutex::operator=(const sf::Mutex&)':|
..\Libraries\SFML-2.0-rc\include\SFML\System\Mutex.hpp|48|instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\stl_vector.h|741|instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]'|
C:\c++ Project\One day\Music.cpp|32|instantiated from here|
..\Libraries\SFML-2.0-rc\include\SFML\System\NonCopyable.hpp|79|error: 'sf::NonCopyable& sf::NonCopyable::operator=(const sf::NonCopyable&)' is private|
..\Libraries\SFML-2.0-rc\include\SFML\System\Mutex.hpp|48|error: within this context|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp||In member function 'sf::Music& sf::Music::operator=(const sf::Music&)':|
..\Libraries\SFML-2.0-rc\include\SFML\Audio\Music.hpp|53|note: synthesized method 'sf::Mutex& sf::Mutex::operator=(const sf::Mutex&)' first required here |
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\vector.tcc||In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, const _Tp&) [with _Tp = sf::Music, _Alloc = std::allocator<sf::Music>]':|
c:\program files\codeblocks\mingw\bin\..\lib\gcc\mingw32\4.4.1\include\c++\bits\vector.tcc|312|note: synthesized method 'sf::Music& sf::Music::operator=(const sf::Music&)' first required here |
||=== Build finished: 8 errors, 0 warnings ===|
Advertisement
The problem is, sf::Music derives from sf::NonCopyable, which is a glorified way of saying the copy constructor has been made private.

Most std libraries depend on there being a public copy constructor ( or there being none, which results in a default public one being created ). End result, you can't use non-copyable objects in most STL containers. You can however, use pointers to them.

The easiest fix is:

sf::Music tempMusic;

becomes

sf::Music *tempMusic = new sf::Music();

The better fix would be to make tempMusic into a unique_ptr<sf::Music> and storing a unique_ptr array in your vector.

The problem is, sf::Music derives from sf::NonCopyable, which is a glorified way of saying the copy constructor has been made private.

Most std libraries depend on there being a public copy constructor ( or there being none, which results in a default public one being created ). End result, you can't use non-copyable objects in most STL containers. You can however, use pointers to them.

The easiest fix is:

sf::Music tempMusic;

becomes

sf::Music *tempMusic = new sf::Music();

The better fix would be to make tempMusic into a unique_ptr<sf::Music> and storing a unique_ptr array in your vector.

I was afraid of that...
Oh well gotta do what you gotta



EDIT::::::::::::::::::::::;

Currently i am doing this code and i am getting no leak but at end of program i get -2147418113 <0x8000FFFF>
From my knowledge i am freeing something badly at Music::Exit()
Also all music is playable so its loaded good...

void Music::InitMusic(App& obj_App)
{
std::ifstream IStream("./Data/Music.txt");
if(IStream.is_open())
{
IStream >> HowManyMusic;
IStream.ignore(2);
for(int i = 0; i < HowManyMusic; i++)
{
std::string FilePath;
IStream >> FilePath;
IStream.ignore(2);
sf::Music* tempMusic = new sf::Music();
if(!(tempMusic->openFromFile(FilePath)))
{
obj_App.obj_ErrorHandle.PrintError("'" + FilePath + " File Could not be opened");
}
MusicList.push_back(tempMusic);
}
}
else
{
obj_App.obj_ErrorHandle.PrintError("'./Data/Music.txt' File Could not be opened");
}
}
void Music::ExitMusic()
{
for(int i = 0; i < HowManyMusic; i++)
{
delete MusicList;
}
MusicList.clear();
}
Is there a good reason why you are using ExitMusic() and not the destructor (~Music)?

Also, don't use "HowManyMusic", use MusicList.size

Finally, you really would be better served making it a vector of auto_ptr or unique_ptr of type music. This will prevent you from having to delete at all.

Is there a good reason why you are using ExitMusic() and not the destructor (~Music)?

Also, don't use "HowManyMusic", use MusicList.size

Finally, you really would be better served making it a vector of auto_ptr or unique_ptr of type music. This will prevent you from having to delete at all.


Its the way i handle application.
To switch level i need to clear music and prepare next level ones.
I modded my code to use MusicList.size() for 'for' loop, did not update post.
I will use auto_ptr or unique_ptr, first time i hear about them tho.
Thanks for help.
About smart pointers:
std::auto_ptr was added in previous C++ standards, and is now deprecated.
std::unique_ptr, std::shared_ptr, and std::weak_ptr are all new ones added in C++11 (and earlier drafts), and may not be available to you unless you are using the latest standard. If you are not using the latest standard, Boost has boost::shared_ptr, boost::weak_ptr, and etc... But you may already have them in the std::tr1:: namespace, as std::tr1::shared_ptr and etc... (I'm not sure how the 'tr' namespace works - it may require doing something to enable it with your compiler).

The point about smart pointers is you don't have to call 'new' or 'delete' manually. Instead of 'new', you use std::make_shared() to make a shared pointer, and then the return result deletes itself once the smart pointer goes out of scope. std::unique_ptr() was forgotten to be added to the standard, but will be patched in later, and you can add it yourself:
#include <memory>
//std::make_unique implementation (it was forgotten in the C++11 standard, and will be added later.
//Once it's added, I can just remove this from here.
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}


There is no std::make_weak() because weak_ptrs() are obtained from shared_ptrs.

std::unique_ptr - Manages an object on its own - it alone controls the lifetime of the object. When std::unique_ptr goes out of scope, the memory is freed.
std::shared_ptr - Manages the lifetime of an object, possibly sharing ownership with other std::shared_ptrs. When every shared_ptr pointing to the same piece of data goes out of scope, then the data is released.
std::weak_ptr - Doesn't manage the lifetime of an object, but points to data held by std::shared_ptr. When all the shared_ptrs go out of scope, then the data is released, and any weak_ptrs still in existence safely throw an exception if the data is attempted to be accesses (instead of unpredictable results).

These declare the intent of the coder better:
std::unique_ptr = I own this object, nobody else owns it _or_ uses it.
std::shared_ptr = I own this object, possibly with shared ownership (through other std::shared_ptrs), and possibly with shared use (through weak_ptrs).
std::weak_ptr = I don't own this object, I just use it.
Regular raw pointer '*' = I don't own this object, I just use it (only use if the pointer's lifetime is garunteed to be longer than the class containing it)

"With the stack, the default is: Clean, Safe, Fast." - Herb Sutter
With local function variables and member-variables, they are automaticly leak-safe and exception-safe. Their destructors are garunteed to be called no matter what, even if the class owning the member variable throws an exception, or if the function with the local variable throws an exception.

In C++, if you use the stack whenever possible, and smart pointers the rest of the time, you (almost) never need to manage the lifetime of an object explicitely.

If you need to optimize the code, then use new and delete and raw pointers, but encapsulate it in objects so that it can't possibly leak out for the end user programmer. But! Default to using the stack first, smart pointers second, and ideally raw memory management never. Smart pointers are very very compact and fast anyway, so 99% of the time, it's premature optimization. But 1% of the time, it is valid and needed.
Actually, the newest XCode, GCC, MingW ( I believe ) and Visual Studio 2010 all support shared_ptr and unique_ptr.
That's what I meant convey to say by this line:
"std::unique_ptr, std::shared_ptr, and std::weak_ptr are all new ones added in C++11 (and earlier drafts), and may not be available to you unless you are using the latest standard." (Buried in a block of text) wink.png

Clang, GCC/MinGW, and Visual Studio 2010 are all using the latest standard (C++11) - which is why they support shared_ptr and unique_ptr. They don't support the standard 100%, but they do support the majority of it. ([size=2]Yes, MinGW supports alot of C++11 as well). They had prior support for some of the standard even before it was standardized, though with GCC/MinGW (and possibly the others) you had to explicitly enable it.

Thanks for clarifying though! I assumed (possibly incorrectly) that the OP would understand that more recent standard-conformance comes with more recent compilers.

Thanks for clarifying though! I assumed (possibly incorrectly) that the OP would understand that more recent standard-conformance comes with more recent compilers.


I've been following it closely and I barely understand ;)

GCC isn't fully compliant, actually there is a fair bit missing. Visual C++ is in a similar boat, with even VC11 ( 2012 ) missing quite a bit. While 2010 was basically TR1 + the most popular bits ( auto, inititalizer lists, rvalue, etc ).

I think Comeau is the only fully compliant C++ compilier and that might not even be true.

You are completely right though, most of the most important bits are there if you are using a reasonably modern compiler.

About smart pointers:
std::auto_ptr was added in previous C++ standards, and is now deprecated.
std::unique_ptr, std::shared_ptr, and std::weak_ptr are all new ones added in C++11 (and earlier drafts), and may not be available to you unless you are using the latest standard. If you are not using the latest standard, Boost has boost::shared_ptr, boost::weak_ptr, and etc... But you may already have them in the std::tr1:: namespace, as std::tr1::shared_ptr and etc... (I'm not sure how the 'tr' namespace works - it may require doing something to enable it with your compiler).

...

Thank you kind sir.

This topic is closed to new replies.

Advertisement