在.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;//不帶參數的lamdaLazy<int> lazyer2 = lazy([]{return 12; });cout << lazyer2.Value() << endl;//帶參數的fucntionstd::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>那么強大,沒有增加線程策略在里面,目前還不想做得更復雜,簡單夠用就行。
c++11 boost技術交流群:296561497,歡迎大家來交流技術。