在 C++11 中,该语言添加了一个名为移动的功能,这正是您遇到的原因。幸运的是,修改代码以使用移动机制非常简单:
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_;
};
这增加了一个“移动构造函数”和一个“移动赋值”,它将 内容从一个移动Texture
到另一个,因此一次只有一个指向给定IDirect3DTexture9
。编译器应该检测到这两个,并停止生成隐式复制构造函数和复制赋值,所以你Texture
不能再被复制,这正是你想要的,因为深度复制 aIDirect3DTexture9
很困难,甚至没有意义。Texture 类现在神奇地修复了。
现在,其他类呢?没有变化。std::map<std::string, Texture>
足够聪明,可以检测到你的类有noexcept
移动操作符,所以它会自动使用它们而不是副本。它还使map
自身可移动但不可复制。并且由于map
是可移动但不可复制的,这会自动使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.