Sign in to follow this  
BaneTrapper

SFML, sf::Music cannot be copied

Recommended Posts

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
[CODE]
std::vector <sf::Music*> MusicList;
MusicList[0] = new sf::Music;
[/CODE]

[CODE]
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");
}
}
[/CODE]

Error report

[CODE]
..\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 ===|
[/CODE] Edited by BaneTrapper

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
[quote name='Serapth' timestamp='1348408107' post='4982914']
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.
[/quote]
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...
[CODE]
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[i];
}
MusicList.clear();
}
[/CODE] Edited by BaneTrapper

Share this post


Link to post
Share on other sites
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. Edited by Serapth

Share this post


Link to post
Share on other sites
[quote name='Serapth' timestamp='1348425636' post='4982994']
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.
[/quote]

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.

Share this post


Link to post
Share on other sites
About smart pointers:
[b]std::auto_ptr[/b] was added in previous C++ standards, and is now deprecated.
[b]std::unique_ptr[/b], [b]std::shared_ptr[/b], and [b]std::weak_ptr[/b] 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 [b]boost::shared_ptr[/b], [b]boost::weak_ptr[/b], and etc... But you may already have them in the [b]std::tr1::[/b] namespace, as [b]std::tr1::shared_ptr[/b] 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 [b]std::make_shared[/b]() to make a shared pointer, and then the return result deletes itself once the smart pointer goes out of scope. [b]std::unique_ptr[/b]() was forgotten to be added to the standard, but will be patched in later, and you can add it yourself:
[code]#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)... ) );
}[/code]

There is no [b]std::make_weak[/b]() because weak_ptrs() are obtained from shared_ptrs.

[b]std::unique_ptr[/b] - 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.
[b]std::shared_ptr[/b] - Manages the lifetime of an object, possibly sharing ownership with other std::shared_ptrs. When [i]every[/i] shared_ptr pointing to the same piece of data goes out of scope, then the data is released.
[b]std::weak_ptr[/b] - 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:
[b]std::unique_ptr[/b] = I own this object, nobody else owns it _or_ uses it.
[b]std::shared_ptr[/b] = I own this object, possibly with shared ownership (through other std::shared_ptrs), and possibly with shared use (through weak_ptrs).
[b]std::weak_ptr[/b] = I don't own this object, I just use it.
[b]Regular raw pointer '*'[/b] = 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)

"[i]With the stack, the default is: Clean, Safe, Fast.[/i]" - 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. [i]But![/i] 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. Edited by Servant of the Lord

Share this post


Link to post
Share on other sites
That's what I meant convey to say by this line:
"[i]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 [u]unless you are using the latest standard[/u].[/i]" (Buried in a block of text) [img]http://public.gamedev.net//public/style_emoticons/default/wink.png[/img]

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[/size]). 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.

Share this post


Link to post
Share on other sites
[quote name='Servant of the Lord' timestamp='1348439172' post='4983032']
Thanks for clarifying though! I assumed (possibly incorrectly) that the OP would understand that more recent standard-conformance comes with more recent compilers.
[/quote]

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

GCC isn't fully compliant, actually there [url="http://gcc.gnu.org/projects/cxx0x.html"]is a fair bit missing[/url]. Visual C++ [url="http://msdn.microsoft.com/en-us/library/hh567368.aspx"]is in a similar boat[/url], 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.

Share this post


Link to post
Share on other sites
[quote name='Servant of the Lord' timestamp='1348432062' post='4983009']
About smart pointers:
[b]std::auto_ptr[/b] was added in previous C++ standards, and is now deprecated.
[b]std::unique_ptr[/b], [b]std::shared_ptr[/b], and [b]std::weak_ptr[/b] 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 [b]boost::shared_ptr[/b], [b]boost::weak_ptr[/b], and etc... But you may already have them in the [b]std::tr1::[/b] namespace, as [b]std::tr1::shared_ptr[/b] and etc... (I'm not sure how the 'tr' namespace works - it may require doing something to enable it with your compiler).

...
[/quote]
Thank you kind sir. Edited by BaneTrapper

Share this post


Link to post
Share on other sites
Just making sf::Music* always makes main return value be -2147418113 <0x8000FFFF>

I cannot find on sfml page how to deal with this error.
I can easily deal with this by making only one sf::Music and reloading it each time you change music.
[CODE]
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
int main()
{
sf::RenderWindow Screen;
Screen.create(sf::VideoMode(800,600,32), "Title of the screen", sf::Style::Default);
bool is_On = true;

//Just making this here will cause the error
sf::Music* tempMusic = new sf::Music;
delete tempMusic;
//Up until here

while(is_On == true)
{
sf::Event EventList;
while(Screen.pollEvent(EventList))
{
switch(EventList.type)
{
case sf::Event::Closed:
is_On = false;
break;
default:
break;
}
}
Screen.clear(sf::Color::White);
Screen.display();
}
Screen.close();
}
[/CODE] Edited by BaneTrapper

Share this post


Link to post
Share on other sites
Why don't you post a minimal complete program that shows the error? That way we can try to reproduce it and help you much better.

By "minimal" I mean that if you were to remove anything from the program, the error wouldn't happen. So for instance you can probably remove anything about the RenderWindow.

Share this post


Link to post
Share on other sites
[quote name='alvaro' timestamp='1348511155' post='4983300']
Why don't you post a minimal complete program that shows the error? That way we can try to reproduce it and help you much better.

By "minimal" I mean that if you were to remove anything from the program, the error wouldn't happen. So for instance you can probably remove anything about the RenderWindow.
[/quote]
I did exactly that. Added #inlucdes if that is what you asked.
I did bare bones of SFML to run and close.

Share this post


Link to post
Share on other sites
I have SFML-1.6 installed. I adapted your code (mostly changing capitalization of methods) and I can't reproduce the problem. SFML-2.0 is not final, precisely because they want people to report problems using it.

I looked at their bug reports and found [url="https://github.com/LaurentGomila/SFML/issues/30"]this[/url], which seems closely related to what you are describing. Read the whole thread to see if other people's experiences might help you. (Notice how much shorter their sample program is than yours: That's what I mean by "minimal".) Edited by alvaro

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this