【问题标题】:How to avoid returning const-ref to a temporary in a cache如何避免将 const-ref 返回到缓存中的临时对象
【发布时间】:2017-09-26 11:46:57
【问题描述】:

我有一个简单的对象缓存:

class ObjectCache
{
public:
    ObjectCache() {}

    const Object& object(const std::string &key) const
    {
        auto it = cache_.find(key);
        if (it != cache_.end())
        {
            return it->second;
        }

        return Object(); // const-ref to temporary
    }

    void insert(const std::string &key, const Object &object)
    {
        cache_[key] = object;
    }

private:
    std:map<std::string, Object> cache_;
};

从缓存中检索时的返回类型是 const ref。

但是,如果未找到密钥,则返回临时的 const ref 并导致调用代码的未定义行为。

如何解决将 const ref 返回到临时对象的问题?

我的一些想法:

  • 插入并返回指针(缓存取得所有权),nullptr 表示未找到
  • 提供 ObjectCache::contains 以便调用代码可以在访问前检查
  • 维护静态或空 Object 成员,并在找不到时返回对它的引用

【问题讨论】:

  • 第四个解决方案是使用std::optionalbooost::optiona 来包装引用。
  • 你可以使用 std::optional.
  • 选项 5) 如果找不到对象,则抛出 ItemNotFoundException。选项 6) 使类可迭代,如果没有找到则返回 end(),否则返回对象的迭代器。
  • 我看不到 optional 的真正好处。
  • 当然std::optional 可以保存引用。这就是std::ref 的意义所在。

标签: c++ caching maps


【解决方案1】:

一个理想的解决方案是保持当前缓存但返回一个指向引用的指针:

class ObjectCache
{
public:
    ObjectCache() {}

    const Object* object(const std::string &key) const
    {
        auto it = cache_.find(key);
        if (it != cache_.end())
        {
            return &(it->second);
        }

        return nullptr;
    }

    void insert(const std::string &key, const Object &object)
    {
        cache_[key] = object;
    }

private:
    std:map<std::string, Object> cache_;
};

这具有避免在堆和内存管理上创建对象的额外好处,但允许调用代码使用未找到的 nullptr。

【讨论】:

    【解决方案2】:

    您可以提供一个接口,允许调用者表达所需的行为:

    #include <map>
    #include <string>
    #include <stdexcept>
    #include <boost/optional.hpp>
    
    struct Object {};
    
    struct NoObject : std::logic_error
    {
        using std::logic_error::logic_error;
    
    };
    
    class ObjectCache
    {
    public:
        ObjectCache() {}
    
        /// Require an object for the corresponding key
        /// @param key
        /// @exception NoObject if the key does not represent an object
        ///  in cache
        const Object& require(const std::string &key) const
        {
            auto it = cache_.find(key);
            if (it != cache_.end())
            {
                return it->second;
            }
            throw NoObject(key);
        }
    
        /// return the object corresponding to key if it exists
        /// If not, call the factory function, store the result and return
        /// the corresponding object
        template<class Factory>
        const Object& acquire(const std::string &key, Factory&& factory) 
        {
            auto it = cache_.find(key);
            if (it == cache_.end())
            {
                it = cache_.emplace(key, factory(key)).first;
            }
            return it->second;
        }
    
    
        /// Return the object corresponding to key if it exists.    
        boost::optional<const Object&> query(const std::string &key) const
        {
            auto it = cache_.find(key);
            if (it != cache_.end())
            {
                return it->second;
            }
            else
            {
                return {};
            }
        }
    
        void insert(const std::string &key, const Object &object)
        {
            cache_[key] = object;
        }
    
    private:
        std::map<std::string, Object> cache_;
    };
    
    int main()
    {
        ObjectCache cache;
    
        // fetch existing or create
        auto& x = cache.acquire("foo", [](std::string const& key){
            return Object();
        });
    
        // fetch existing or exception
        auto& y = cache.require("foo");
    
        // fetch existing if exists
        if(auto z = cache.query("foo"))
        {
            auto&& zz = z.get();
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-06
      • 1970-01-01
      • 1970-01-01
      • 2012-07-18
      • 2010-09-10
      • 1970-01-01
      相关资源
      最近更新 更多