I want to write a ContentManager class which loads and maintains different types of assets for a game (compare with XNA's ContentManager).
My header file looks like the following:
class ContentManager
{
public:
  ContentManager(Direct3D& d3d, const std::string& rootDirectory = "Resource");
 ~ContentManager();
  template<typename T>
  const T& Load(const std::string& assetName);
private:
  Direct3D& d3d_;
  std::string rootDirectory_;
  std::map<std::string, Texture> textures_;
};
As you can see, I have a map for each asset type (only for textures at the moment) and a generic Load<T>() method, which I instantiate explicitly for each asset type I want to store. Load<Texture>() reads an image file from disk (if it's not already in the map), creates a new Texture, inserts it into the map and returns it.
My Texture class basically creates and encapsulates a raw IDirect3DTexture9 to follow the RAII idiom (the destructor calls Release() on the texture_):
class Texture
{
public:
  Texture();
  Texture(Direct3D& d3d, unsigned int width, unsigned int height, 
    const std::vector<unsigned char>& stream);
  ~Texture();
  IDirect3DTexture9* GetD3DTexture() const { return texture_; }
private:
  IDirect3DTexture9* texture_;
};
When testing my code, I realized that each texture was released twice, because (shallow) copies of the Texture objects were created at some point, and the destructor was called for each of these, of course.
Furthermore, although Load<T>() returns a reference to an element of the map, the caller could make a copy himself and trigger the same problem. My thoughts:
Making the copy constructor of
Textureprivate is no solution, since copies are required anyway when creating anstd::pairto insert a new element into the map.Defining a custom copy constructor, which creates a deep copy, doesn't seem to be reasonable at all, since I would need to create a copy of the underlying Direct3D texture, which should really exist only once.
So what are my options here? Could this be solved by using smart pointers? Which type should be stored in the map and which type should Load<T>() return?
                        
With C++11, the language added a feature called moving for exactly the reason you are encountering. And luckily, modifying your code to use move mechanics is amazingly simple:
This adds a "move constructor" and a "move assignment", which will move the content from one
Textureto another, so that only one points to a givenIDirect3DTexture9at a time. The compiler should detect these two, and stop generating the implicit copy constructor and copy assignment, so yourTexturecan no longer be copied, which is exactly what you wanted, since deep-copying aIDirect3DTexture9is hard and doesn't even really make sense. The Texture class is now magically fixed.Now, what about the other classes? No changes.
std::map<std::string, Texture>is smart enough to detect that your class hasnoexceptmove operators, and so it will use them automatically instead of copies. It also makes themapitself movable but not copiable. And since themapis movable but not copiable, that automagically makesContentManagermovable but not copiable. Which makes sense when you think about it, moving content around is fine, but you don't want to copy all of that. So those don't need any changesNow, since rvalues is obviously a new concept to you, here's a crash course: