其他分享
首页 > 其他分享> > C:存储复制操作不合理或不可能的资源

C:存储复制操作不合理或不可能的资源

作者:互联网

我想编写一个ContentManager类,为游戏加载和维护不同类型的资产(与XNA’s ContentManager比较).
我的头文件如下所示:

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_;
};

正如您所看到的,我有一个每种资产类型的地图(目前仅针对纹理)和一个通用的Load< T>()方法,我为我想要存储的每种资产类型明确实例化.加载< Texture>()从磁盘读取图像文件(如果它尚未在地图中),创建一个新的纹理,将其插入到地图中并返回它.

我的Texture类基本上创建并封装了一个原始IDirect3DTexture9来跟随RAII习惯用法(析构函数在texture_上调用Release()):

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_;
};

在测试我的代码时,我意识到每个纹理都被释放了两次,因为在某些时候创建了Texture对象的(浅)副本,当然也为每个纹理调用了析构函数.

此外,尽管Load< T>()返回对地图元素的引用,但调用者可以自己制作副本并触发相同的问题.我的想法:

>制作Texture private的复制构造函数是没有解决方案,因为在创建std :: pair以将新元素插入到地图时,无论如何都需要复制.
>定义创建深层副本的自定义复制构造函数似乎根本不合理,因为我需要创建底层Direct3D纹理的副本,该纹理应该只存在一次.

那么我的选择是什么?这可以通过使用智能指针来解决吗?哪个类型应该存储在地图中,哪个类型应该加载< T>()返回?

解决方法:

使用C 11,语言添加了一个名为moving的功能,正是因为您遇到的原因.幸运的是,修改代码以使用移动机制非常简单:

class Texture
{
public:
  Texture() noexcept;
  Texture(Direct3D& d3d, unsigned int width, unsigned int height, 
    const std::vector<unsigned char>& stream);

  Texture(Texture&& rhs) noexcept
  : texture_(rhs.texture_) //take the content from rhs
  {rhs.texture_ = nullptr;} //rhs no longer owns the content

  Texture& operator=(Texture&& rhs) noexcept
  {
    Clear(); //erase previous content if any
    texture_ = rhs.texture_; //take the content from rhs
    rhs.texture_ = nullptr; //rhs no longer owns the content
    return *this;
  }

  ~Texture() noexcept {Clear();}

  IDirect3DTexture9* GetD3DTexture() const noexcept { return texture_; }

private:
  void Clear() noexcept; //does nothing if texture_ is nullptr
  IDirect3DTexture9* texture_;
};

这会添加一个“移动构造函数”和一个“移动赋值”,它将内容从一个纹理移动到另一个纹理,这样一次只有一个指向给定的IDirect3DTexture9.编译器应检测这两个,并停止生成隐式复制构造函数和复制赋值,因此无法再复制您的纹理,这正是您想要的,因为深度复制IDirect3DTexture9很难,甚至没有意义.现在神奇地修复了Texture类.

现在,其他课程怎么样?没有变化. std :: map< std :: string,Texture>足够聪明,可以检测到您的类没有移动运算符,因此它将自动使用它们而不是副本.它还使地图本身可移动但不可复制.由于地图是可移动但不可复制的,因此可以自动使ContentManager移动但不可复制.当你考虑它时有意义,移动内容很好,但你不想复制所有这些.所以那些不需要任何改变

现在,因为对你来说rvalues显然是一个新概念,所以这是一个速成课程:

Texture getter(); //returns a temporary Texture
Texture a = getter(); //since the right hand side is a temporary,
                        //the compiler will try to move construct it, and only 
                        //copy construct if it can't be moved.
a = getter(); //since the right hand side is a temporary,
                        //the compiler will try to move assign it, and only 
                        //copy assign if it can't be moved.

void setter1(Texture&); //receives a reference to an outside texture object
setter1(a); //works exactly as it always has
setter1(getter()); //compiler error, reference to temporary
setter1(std::move(a)); //compiler error, passing rreference && instead of lreference &.

void setter2(Texture); //receives a local texture object
setter2(a); //compiler error, no copy constructor
setter1(getter()); //creates the Texture by moving the data from the temporary
setter2(std::move(a)); //The compiler moves the content from a to the function;
                      //the function receives the content previously held by a, and 
                      //a now has no content.  Careful not to read from a after this.

void setter3(Texture&&); //receives a reference to a temporary texture
setter3(a); //compiler error, a is not a temporary
setter3(getter()); //function receives reference to the temporary, all is good
setter3(std::move(a)); //function thinks a is temporary, and will probably remove 
                       //it's content. Careful not to read from a after this.   

标签:move-constructor,c,directx,directx-9
来源: https://codeday.me/bug/20190825/1719884.html