c++11實現c++14的optional


  c++14中將包含一個std::optional類,它的功能和用法和boost的optional類似。optional<T>內部存儲空間可能存儲了T類型的值也可能沒有存儲T類型的值,只有當optional被T初始化之后,這個optional才是有效的,否則是無效的,它實現了未初始化的概念。

optional的應用場景

函數返回無效對象
  有時根據某個條件去查找對象時,如果查找不到對象時就會返回一個無效值,這不表明函數執行失敗,而是表明函數正確執行了,但是結果卻不是有用的值,這時就可以返回一個未初始化的optional對象出去,在外面判斷這個optional對象是否有效對象是否被初始化,如果沒有被初始化就表明這個值是無效的。
boost中的optional就實現了這種未初始化的概念,boost.optional的基本用法很簡單:

optional<int> op;
if(op)
    cout<<*op<<endl;

optional<int> op1 = 1;
if(op1)
    cout<<*op1<<endl;

  第一個op由於沒有被初始化,所以它是一個無效值,將不會輸出打印信息,第二個op被初始化為1,所以它是一個有效值,將會輸出1。optional經常用於函數返回值,像boost.property_tree中就有很多optional接口(關於boost.property_tree可以參考我前面博文的介紹:),比如get_child_optional接口,返回一個optional<ptree>對象,外面需要判斷它是否是一個有效值來確定是否取到了對應的子節點。

c++11實現optional

  c++11中目前還沒有optional,在c++14中將會增加std::optional功能和用法和boost.optional類似。在c++14中的std::optional出來之前,如果不想依賴boost庫的話,就用c++11實現一個optional,也不是難事。

c++11實現optional需要注意的問題

1.內部存儲空間
  由於optional<T>需要容納T的值,所以需要一個緩沖區保存這個T,這個緩沖區不能用普通的char數組,需要用內存對齊的緩沖區,這里還是采用std::aligned_storage,關於這個可以參考我前面的博文中對std::aligned_storage的討論。

2.拷貝構造函數和賦值構造函數

  需要注意拷貝和賦值時,內部狀態和緩沖區銷毀的問題。內部狀態用來標示該optional是否被初始化,當已經初始化時需要先將緩沖區清理一下。需要增加右值版本優化效率。
  來看看具體的實現吧:

#include <type_traits>

template<typename T>
class Optional
{
    using data_t = typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type;
public:
    Optional() : m_hasInit(false) {}
    Optional(const T& v)
    {
        Create(v);
    }

    Optional(T&& v) : m_hasInit(false)
    {
        Create(std::move(v));
    }

    ~Optional()
    {
        Destroy();
    }

    Optional(const Optional& other) : m_hasInit(false)
    {
        if (other.IsInit())
            Assign(other);
    }

    Optional(Optional&& other) : m_hasInit(false)
    {
        if (other.IsInit())
        {
            Assign(std::move(other));
            other.Destroy();
        }
    }

    Optional& operator=(Optional &&other)
    {
        Assign(std::move(other));
        return *this;
    }

    Optional& operator=(const Optional &other)
    {
        Assign(other);
        return *this;
    }

    template<class... Args>
    void emplace(Args&&... args)
    {
        Destroy();
        Create(std::forward<Args>(args)...);
    }

    bool IsInit() const { return m_hasInit; }

    explicit operator bool() const { return IsInit(); 

}

    T& operator*()
    {
        return *((T*) (&m_data));
    }

    T const& operator*() const
    {
        if (IsInit())
        {
            return *((T*) (&m_data));
        }

        throw std::exception("");
    }

    bool operator == (const Optional<T>& rhs) const
    {
        return (!bool(*this)) != (!rhs) ? false : (!bool(*this) ? true : (*(*this)) == (*rhs));
    }

    bool operator < (const Optional<T>& rhs) const
    {
        return !rhs ? false : (!bool(*this) ? true : (*(*this) < (*rhs)));
    }

    bool operator != (const Optional<T>& rhs)
    {
        return !(*this == (rhs));
    }
private:
    template<class... Args>
    void Create(Args&&... args)
    {
        new (&m_data) T(std::forward<Args>

(args)...);
        m_hasInit = true;
    }

    void Destroy()
    {
        if (m_hasInit)
        {
            m_hasInit = false;
            ((T*) (&m_data))->~T();
        }
    }

    void Assign(const Optional& other)
    {
        if (other.IsInit())
        {
            Copy(other.m_data);
            m_hasInit = true;
        }
        else
        {
            Destroy();
        }
    }

    void Assign(Optional&& other)
    {
        if (other.IsInit())
        {
            Move(std::move(other.m_data));
            m_hasInit = true;
            other.Destroy();
        }
        else
        {
            Destroy();
        }
    }

    void Move(data_t&& val)
    {
        Destroy();
        new (&m_data) T(std::move(*((T*) 

(&val))));
    }

    void Copy(const data_t& val)
    {
        Destroy();
        new (&m_data) T(*((T*) (&val)));
    }

private:
    bool m_hasInit;
    data_t m_data;
};

測試代碼:

void TestOptional()
{
    Optional<string> a("ok");
    Optional<string> b("ok");
    Optional<string> c("aa");
    c = a;
    if (c<a)
        cout << "<" << endl;

    if (a == b)
        cout << "=" << endl;

        map<Optional<string>, int> mymap;
    mymap.insert(std::make_pair(a, 1));
    mymap.insert(std::make_pair(c, 2));

    auto it = mymap.find(a);
    cout << it->second << endl;
}    

可以看到用法和boost.optional的用法保持一致,實現起來也比較簡單。

 

如果你覺得這篇文章對你有用,可以點一下推薦,謝謝。

c++11 boost技術交流群:296561497,歡迎大家來交流技術。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM