6
votes

I am using Visual Studio 2012. I have a map that looks like this:

std::map<std::string,std::map<std::unique_ptr<sf::Sound>,std::unique_ptr<sf::SoundBuffer>>> listSoundContainer;

I'm trying to insert data like this:

std::unique_ptr<sf::SoundBuffer> soundBuffer(new sf::SoundBuffer());
if (soundBuffer->loadFromFile("assets/sound/" + _fileName) != false)
{
    std::unique_ptr<sf::Sound> sound(new sf::Sound(*soundBuffer));
    typedef std::map<std::unique_ptr<sf::Sound>, std::unique_ptr<sf::SoundBuffer>> innerMap;
    listSoundContainer[_fileName].insert(innerMap::value_type(std::move(sound), std::move(soundBuffer)));               
}

and im getting the following error at compile time:

microsoft visual studio 11.0\vc\include\utility(182): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 1> with 1>
[ 1> _Ty=sf::Sound 1> ] 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\memory(1447) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr' 1> with 1> [ 1> _Ty=sf::Sound 1> ] 1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\xmemory0(617) : see reference to function template instantiation 'std::pair<_Ty1,_Ty2>::pair(std::pair<_Ty1,_Ty2> &&,void **)' being compiled 1> with 1> [ 1>
_Ty1=const std::unique_ptr, 1> _Ty2=std::unique_ptr, 1> _Kty=std::unique_ptr, 1> _Ty=std::unique_ptr 1> ]

I have also tried to insert data using make_pair with the same problem. What am I missing? Ive been trying to solve this problem for 2 hours now and can't get my head around it.

I can actually solve this problem by NOT using smart pointers:

sf::SoundBuffer* soundbuffer = new sf::SoundBuffer();
soundbuffer->loadFromFile(_file);
sf::Sound* sound = new sf::Sound(*soundbuffer);
typedef std::map<sf::SoundBuffer*, sf::Sound*> mapType;
listSound[_file].insert(mapType::value_type(soundbuffer, sound));
2
I think maybe another problem might be that map::value_type you are using. Documentation says it transforms the Key value in a constant - meneldal
Using a unique_ptr as a map's key type is very strange, if not impossible because of the reason stated above by meneldal. Even if you manage to get the code to compile, how would you ever find something with a matching key? unique_ptrs are after all, unique. Even if you managed to somehow construct another unique_ptr managing the same raw pointer, as soon as you're done finding or indexing using operator[], the second unique_ptr would be destroyed, thereby deleting the pointer it manages, You need to come up with some other data structure. - Praetorian
Praetorian: I have a polymorphic key and I don't want to store it as a shared_ptr. The comparison forwards to the key's operator<(). - chila

2 Answers

2
votes

Look at the template definition for std::map:

template<
    class Key,
    class T,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<std::pair<const Key, T> >
> class map;

And now lets look at how you try to instantiate it:

std::map<
    std::string, 
    std::map<
        std::unique_ptr<sf::Sound>, 
        std::unique_ptr<sf::SoundBuffer>
    >
> 
listSoundContainer

The problem here is that a std::unique_ptr<sf::Sound> cannot act as a key.

What you seem trying to do is to make some kind of list of std::pair<std::unique_ptr<sf::Sound>, std::unique_ptr<sf::SoundBuffer>>

I would suggest using this instead:

std::map<
    std::string, 
    std::list<
        std::pair<
            std::unique_ptr<sf::Sound>, 
            std::unique_ptr<sf::SoundBuffer>
        >
    >
> 
listSoundContainer
-2
votes

Smart pointers should not be used in combination with STL containers.

The background is that smart pointers do not behave as expected by the STL-containers. For instance, the STL expects source objects of a copy operation to remain unchanged. This is not the case with smart pointers. This can lead to strange effects as you are experiencing...

EDIT: My answer was not fully correct. Since C++11 it is possible to use smart pointers, e.g. unique_ptr, with STL-containers.