首页 > 解决方案 > 使用 unique_ptr 并返回引用,或者我应该使用 shared_ptr 并在需要时制作副本

问题描述

我有一个缓存,它将对象的唯一 ptrs 存储在无序映射中,并为缓存的用户返回对象的引用。它可以正常工作,存储对象直到它们超出范围。

缓存实现如下:

在缓存中存储对象:

template<typename T>
template<typename... Args>
void ResourceCache<T>::add(const std::string& name, Args... args)
{
    m_cache->try_emplace(name, std::make_unique<T>(args...));
}

从缓存中获取对象:

template<typename T>
T& ResourceCache<T>::getCachedElement(const std::string& name) const
{
    auto it = m_cache->find(name);

    if(it != m_cache->end())
        return *it->second;

    throw "resource not found";
}

但是现在我遇到了一个问题,即引用并不总是我想从缓存中获取的,例如:

我有以下对象:

class GameObject
{
public:
    void translate(const cheetah::Vector3f& position);
protected:
    Quaternion m_rotation;
    Vector3f m_position;
};

假设我希望对象具有纹理,目前对我来说唯一的方法是添加成员引用

Texture& m_texture

这将导致我不得不

  1. 将纹理传递给每个对象的构造函数,即使它们不需要纹理。
  2. 创建一个继承自 GameObject 并添加 Texture 成员和构造函数的 TexturedGameObject。
  3. 使用共享指针而不是唯一指针并且能够返回一个副本

现在我的问题是

在这种特定情况下,什么被视为最佳实践?我应该使用上述选项之一还是错过了更好的选择?

我知道我的问题不是最具体的,但我正在自己学习 c++,如果能得到别人对此的看法会很好。

标签: c++

解决方案


假设ResourceCache成立Texture,这是我的想法。一般来说,似乎没有一种最佳解决方案。

  1. 将纹理传递给每个对象的构造函数,即使它们不需要纹理。
    • 您需要传递一个虚拟对象,因此如果您想采用这种方式,我建议您将其保留为原始指针
    • 通过这样做,您可以检查它是否真的有一个指针,因为它可以是nullptr
    • 注意无论是引用还是指针,您都应该确保它的寿命ResourceCache超过所有GameObject- 必须手动管理生命周期
  2. 创建一个继承自 GameObject 并添加 Texture 成员和构造函数的 TexturedGameObject。
    • 这可能是一个选择,但我认为这更像是一个设计问题
  3. 使用共享指针而不是唯一指针并且能够返回一个副本
    • 这会很好用
    • 安全(没有双重删除/悬空指针等问题)
    • 共享指针有开销

推荐阅读