分享

一个和c#中Lazy<T>类似的c++ Lazy<T>类的实现

 quasiceo 2014-01-06
一个和c#中Lazy<T>类似的c++ Lazy<T>类的实现
 在.net 4.0中增加一个延迟加载类Lazy<T>,它的作用是实现按需延迟加载,也许很多人用过。一个典型的应用场景是这样的:当初始化某个对象时,该对象引用了一个大对象,需要创建,这个对象的创建时需要较长的时间,同时也需要在托管堆上分配较多的空间,这样可能会在初始化时变得很慢,尤其是UI应用时,会导致用户体验很差。其实狠多时候并不需要马上就获取大数据,只是在需要时获取,这种场景就很适合延迟加载了。先看看c#中Lazy<T>如何使用的吧:
class LargeObject
{
    public int InitializedBy { get { return initBy; } }
    int initBy = 0;
    public LargeObject(int initializedBy)
    {
        initBy = initializedBy;
        Console.WriteLine("LargeObject was created on thread id {0}.", initBy);
    }
    public long[] Data = new long[100000000];
}
class TestLazy
{
    Lazy<LargeObject> lazyLargeObject = null;
    public TestLazy()
    {
        //创建一个延迟加载对象
        lazyLargeObject = new Lazy<LargeObject>(InitLargeObject);
    }
    public void ReallyLoad()
    {
        //此时真正加载
        lazyLargeObject.Value;
        Console.WriteLine("lazy load big object");
        //do something
    }
}
void Test()
{
    TestLazy t = new TestLazy();
    t.ReallyLoad(); //这时,真正延迟加载时才会打印"lazy load big object"
}
  c++中目前还没有类似的Lazy<T>延迟加载类,其实延迟加载类内部用到了lamda表达式,将函数封装到lamda表达式中去,而不是马上求值,而是在需要的时候再调用lamda表达式去求值。c++11 中有lamda表达式和function,正好做这个事情,看看c++11如何实现类似c#的Lazy<T>延迟加载类吧。
#include <boost/optional.hpp>
template<typename T>
struct Lazy
{
    Lazy(){}
    template <typename Func, typename... Args>
    Lazy(Func& f, Args && ... args)
    {
        m_func = [&f, &args...]{return f(args...); };
    }
    T& Value()
    {
        if (!m_value.is_initialized())
        {
            m_value = m_func();
        }
        return *m_value;
    }
    bool IsValueCreated() const
    {
        return m_value.is_initialized();
    }
private:
    std::function<T()> m_func;
    boost::optional<T> m_value;
};
template<class Func, typename... Args>
Lazy<typename std::result_of<Func(Args...)>::type>
    lazy(Func && fun, Args && ... args)
{
    return Lazy<typename std::result_of<Func(Args...)>::type>(std::forward<Func>(fun), std::forward<Args>(args)...);
}
再看看测试代码:
struct BigObject
{
    BigObject()
    {
        cout << "lazy load big object" << endl;
    }
};
struct MyStruct
{
    MyStruct()
    {
        m_obj = lazy([]{return std::make_shared<BigObject>(); });
    }
    void Load()
    {
        m_obj.Value();
    }
    Lazy< std::shared_ptr<BigObject>> m_obj;
};
int Foo(int x)
{
    return x * 2;
}
void TestLazy()
{
    //带参数的普通函数
    int y = 4;
    auto lazyer1 = lazy(Foo, y);
    cout << lazyer1.Value() << endl;
    //不带参数的lamda
    Lazy<int> lazyer2 = lazy([]{return 12; });
    cout << lazyer2.Value() << endl;
    //带参数的fucntion
    std::function < int(int) > f = [](int x){return x + 3; };
    auto lazyer3 = lazy(f, 3);
    cout << lazyer3.Value() << endl;
    //延迟加载大对象
    MyStruct t;
    t.Load();
}
输出结果:
8
12
6
lazy laod big object
  这个Lazy<T>类可以接收lamda表达式和function,实现按需延迟加载。和c#的Lazy<T>用法类似。不过还没c#中Laze<T>那么强大,没有增加线程策略在里面,目前还不想做得更复杂,简单够用就行。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多