C++ C++;11智能指针语义
我使用指针已经有几年了,但直到最近我才决定转向C++11的智能指针(即唯一、共享和弱)。我对它们做了一些研究,得出以下结论:C++ C++;11智能指针语义,c++,pointers,c++11,smart-pointers,C++,Pointers,C++11,Smart Pointers,我使用指针已经有几年了,但直到最近我才决定转向C++11的智能指针(即唯一、共享和弱)。我对它们做了一些研究,得出以下结论: 独特的指针非常棒。它们管理自己的内存,并且与原始指针一样轻量级。与原始指针相比,尽可能选择唯一的\u ptr 共享指针很复杂。由于引用计数,它们有很大的开销。通过不断的参考传递它们,或者为自己的错误感到遗憾。它们不是邪恶的,但应该谨慎使用 共享指针应该拥有对象;当不需要所有权时,使用弱指针。锁定弱\u ptr的开销与共享\u ptr复制构造函数的开销相当 继续忽略auto
class TextureManager {
public:
const Texture& texture(const std::string& key) const
{ return textures_.at(key); }
private:
std::unordered_map<std::string, Texture> textures_;
};
class GameObject {
public:
void set_texture(const Texture& texture)
{ texture_ = std::unique_ptr<Texture>(new Texture(texture)); }
private:
std::unique_ptr<Texture> texture_;
};
类纹理管理器{
公众:
常量纹理和纹理(常量标准::字符串和键)常量
{return.at(key);}
私人:
std::无序的贴图纹理;
};
类游戏对象{
公众:
空集纹理(常量纹理和纹理)
{texture_uu=std::unique_ptr(新纹理(纹理));}
私人:
标准::独特的纹理;
};
然而,我对此的理解是,一个新的纹理将从传递的引用中复制构建,然后由unique_ptr拥有。这给我的印象是非常不受欢迎的,因为我会拥有和使用它的游戏对象一样多的纹理副本——击败指针点(没有双关语)class TextureManager {
public:
const std::shared_ptr<Texture>& texture(const std::string& key) const
{ return textures_.at(key); }
private:
std::unordered_map<std::string, std::shared_ptr<Texture>> textures_;
};
class GameObject {
public:
void set_texture(const std::shared_ptr<Texture>& texture)
{ texture_ = texture; }
private:
std::weak_ptr<Texture> texture_;
};
类纹理管理器{
公众:
const std::shared_ptr&texture(const std::string&key)const
{return.at(key);}
私人:
std::无序的贴图纹理;
};
类游戏对象{
公众:
空集纹理(常量标准::共享纹理)
{texture\=texture;}
私人:
标准:弱纹理;
};
与独特的_ptr不同,我不必复制构建纹理本身,但渲染游戏对象的成本很高,因为每次我都必须锁定弱的_ptr(与复制构建新的共享_ptr一样复杂)抱歉读了这么长时间,谢谢你抽出时间 即使在C++11中,原始指针作为对对象的非所有者引用仍然是完全有效的。在你的例子中,你说的是“让我们假设纹理保证比它们的指针寿命长。”这意味着在游戏对象中使用纹理的原始指针是完全安全的。在纹理管理器中,可以自动(在保证内存中恒定位置的容器中)存储纹理,也可以存储在
unique_ptr
s的容器中
如果指针保证的有效期无效,则将纹理存储在管理器中的
shared_ptr
中,并在游戏对象中使用shared_ptr
s或弱_ptr
s,这取决于游戏对象对纹理的所有权语义。您甚至可以将其反转—在对象中存储shared_ptr
s,在管理器中存储weak_ptr
s。这样,管理器将充当缓存—如果请求纹理且其弱\u ptr
仍然有效,它将给出该纹理的副本。否则,它将加载纹理,发出一个共享的\u ptr
并保持一个弱的\u ptr
您可以在存储纹理的位置有一个std::unique的std::map。然后,您可以编写一个get方法,通过名称返回对纹理的引用。这样,如果每个模型都知道其纹理的名称(它应该知道),则可以简单地将该名称传递到get方法中,并从贴图中检索引用
class TextureManager
{
public:
Texture& get_texture(const std::string& key) const
{ return *textures_.at(key); }
private:
std::unordered_map<std::string, std::unique_ptr<Texture>> textures_;
};
类纹理管理器
{
公众:
纹理和获取纹理(常量标准::字符串和键)常量
{return*纹理在(键);}
私人:
std::无序的贴图纹理;
};
然后,您可以在游戏对象类中使用纹理,而不是纹理*,weak_ptr et
using TextureRef = Texture const*;
...
TextureRef TextureManager::texture(const std::string& key) const;
TextureRef t{texture_manager.texture("grass")};
// You can treat t as a value. You can pass it, return it, compare it,
// or put it in a container.
// But you use it like a pointer.
double aspect_ratio{t->get_aspect_ratio()};
struct Texture
{
Texture(std::string const& texture_name):
pimpl_{texture_manager.texture(texture_name)}
{
// Either
assert(pimpl_);
// or
if (not pimpl_) {throw /*an appropriate exception */;}
// or do nothing if TextureManager::texture() throws when name not found.
}
...
double get_aspect_ratio() const {return pimpl_->get_aspect_ratio();}
...
private:
TextureImpl const* pimpl_; // invariant: != nullptr
};
Texture t{"grass"};
// t has both value semantics and value syntax.
// Treat it just like int (if int had member functions)
// or like std::string (except lighter weight for copying).
double aspect_ratio{t.get_aspect_ratio()};