簡體   English   中英

用於STL容器的Const鎖包裝器

[英]Const lock wrapper for STL containers

我正在嘗試為std::vector (或STL中的任何其他容器,如果可能的話)創建一個包裝器,它可以“鎖定”和“解鎖”它所持有的向量的常量狀態。

例如,如果我創建該包裝器的對象,我希望能夠執行以下操作:

int main()
{
    ConstLockVectorWrapper<int> myWrapper(std::vector<int>{});  // Here I pass an empty vector in the constructor parameters,
                                                                // which means that my wrapper will be holding an empty vector

                                                                // By default the vector inside my wrapper is not locked,
                                                                // I can change its size and the values that it holds

    myWrapper.get().push_back(10); // ok
    myWrapper.get().push_back(20); // ok
    myWrapper.get().at(0) = 5; // ok

    print(myWrapper.get()); // Prints 5 20



    myWrapper.lock(); // Now I made the vector inside my wrapper unchangable 



    myWrapper.get().push_back(30); // error, the vector is locked
    myWrapper.get().at(0) = 55; // error

    print(myWrapper.get()); // ok



    myWrapper.unlock(); // Now I can change my vector's size and its values again


    _getch();
    return 0;
}

唯一的解決方案(不幸的是,我沒有),是在包裝類中創建一個const引用( const std::vector<T> & )和一個常規引用​​( td::vector<T> & ) ,並將它們綁定到我們的包裝類中的主向量。

所以,這就是我所做的:

template <typename T>
class ConstLockVectorWrapper {
public:
    ConstLockVectorWrapper(const std::vector<T> & vec)
        : wrappedVector(vec), wrappedVectorRef(wrappedVector), wrappedVectorConstRef(wrappedVector), constLock(false)
    {}

    void lock()
    {
        if (constLock) // if the vector is already locked, we just exit the function
            return;

        // else we lock the vector
        constLock = true;
    }

    void unlock()
    {
        if (!constLock) // if the vector is already unlocked (changable), we just exit the function
            return;

        // else we unlock the vector
        constLock = false;
    }

    return_type get() // I need to return a const std::vector<T> & if constLock == true, and std::vector<T> & otherwise, what return type should I put in here?
    {
        if (constLock)
            return wrappedVectorConstRef;
        else
            return wrappedVectorRef;
    }

private:
    bool constLock;
    std::vector<T> wrappedVector;

    // refs
    std::vector<T> & wrappedVectorRef;
    const std::vector<T> & wrappedVectorConstRef;
};

當然,它不起作用。 只是因為我不知道在get()函數的返回類型中放入什么。

我試過使用尾隨返回類型,但沒有工作:

template <typename T>
class ConstLockVectorWrapper {
public:
    // ...

private:
    bool constLock;
    std::vector<T> wrappedVector;

    // refs
    std::vector<T> & wrappedVectorRef;
    const std::vector<T> & wrappedVectorConstRef;

public:
    auto get() -> decltype((constLock ? wrappedVectorConstRef : wrappedVectorRef)) 
    {
        if (constLock)
            return wrappedVectorConstRef;
        else
            return wrappedVectorRef;
    }
};

我無法想出任何實際可行的解決方案,因為我還不擅長C ++。

所以我要求你幫助解決我的問題。 任何建議或提示來解決這個問題將不勝感激!

謝謝

PS

我的主要目標是使我的包裝容器類型獨立,因此它可以“鎖定”和“解鎖”它所持有的容器的const狀態,而與其類型無關。

這是我在第一個代碼片段中使用的print()函數:

template <typename Container>
void print(const Container & c)
{
    for (const auto & var : c)
        std::cout << var << std::endl;
}

從根本上說,方法總是返回相同的東西。 相同的類型。 每次。 在C ++中,有時候一個方法返回一種類型,而另一種類型則返回另一種類型是不可能的。 C ++不能這樣工作。

因此,最初的方法是讓get()返回一個具有狀態的代理對象。 大致使用您問題中的相同類和名稱:

class return_type {

      bool is_const;
      std::vector<T> &wrapped_vec;

public:
      return_type(bool is_constArg,
                  std::vector<T> &wrapped_vecArg)
          : is_const(is_constArg), wrapped_vec(wrapped_vecArg)
      {
      }

      void push_back(T &&t)
      {
           if (is_const)
                throw std::runtime_error(); // Or, whatever...
           wrapped_vec.push_back(std::forward<T>(t));
      }

      // return_type will have to implement, and baby-sit all other
      // methods you wish to invoke on the underlying vector.
};

return_type get()
{
    return return_type(constLock);
}

這很簡單,但粗糙而且有點單調乏味。 您必須實現需要在return_type代理中使用的每個std :: vector方法。

更好的方法是利用C ++ 11 lambdas。 這將避免重新實現每個輪子的需要,代價是一些額外的代碼膨脹。 但是,很重要。 RAM很便宜,如今。 現在,您將在包裝器中實現兩個模板方法: get_const()get_mutable() ,而不是get()return_type 它們中的每一個都接受一個lambda參數並調用它,如果一切順利,將包裝的向量作為參數傳遞給它:

      template<typename lambda>
      void get_mutable(lambda &&l)
      {
           if (constLock)
                throw std::runtime_error(); // Or, whatever...

           l(wrapped_vec);
      }

      template<typename lambda>
      void get_const(lambda &&l)
      {
           l(const_cast<const std::vector<T> &>(wrapped_vec));
      }

您現在唯一需要決定的是您是否需要訪問可變或常量向量,並選擇正確的getter:

myWrapper.get_mutable( [&](std::vector<int> &v) { v.push_back(10); } );

如果此時向量被鎖定,則get_mutable()會拋出異常。 否則它將向量傳遞給lambda。 你的lambda做它想要的任何東西,可以是push_back() ,或其他任何東西,然后返回。

但是,如果您只需要對向量的只讀訪問權限,請使用get_const()

int s;

myWrapper.get_const( [&](const std::vector<int> &v) { s=v.size(); } );

請注意,在調用lambda之前, get_const()會關注const_cast向量,因此lambda將無法修改它。 這將在編譯時強制執行。

通過一些額外的工作,也可以稍微清理一下,讓getter也返回lambda返回給調用者的任何東西,這樣可以做到這樣的事情:

int s=myWrapper.get_const( [&](const std::vector<int> &v) { return v.size(); } );

有可能讓get_const()get_mutable()足夠聰明,以確定lambda是否返回了某些內容,並愉快地將其傳遞給調用者,無論它是什么。 我想,如何做到這一點必須是stackoverflow.com上的另一個問題

PS如果你沒有C ++ 11,你可以讓get_const()get_mutable()返回包裝的向量(用get_mutable()驗證它沒有被鎖定)。 這真的完成了同樣的事情。 關鍵點在於,由於C ++的工作方式,您必須提前消除是否需要持續或可變訪問的歧義。

我不久前正在研究類似的問題。 在多線程環境中,根據您是在閱讀還是寫作,有時可以更有效地使用不同類型的鎖。 但鎖定是完全合作的。 可以獲得只讀鎖定但仍然意外地寫入對象。

我正在探索的一個解決方案是,不是從對象獲取只讀 ,而是獲取對象的只讀包裝 ,這樣不僅對象只讀被鎖定,它也只能調用只讀const )對象的方法。

我使用的基本包裝是這樣的:

template<typename T>
class ConstWrapper
{
    T& v;

public:
    ConstWrapper(T& v): v(v) {}

    T const& operator* () const { return v; } // return const reference
    T const* operator->() const { return &v;} // return const pointer
};

通過重載*->運算符,您可以獲得一種調用封閉對象方法的傳遞能力 - 但是使用指針語義(盡管它不是指針)。

std::vector<int> v {1, 2, 3, 4}; // not const

ConstWrapper<std::vector<int>> cv(v); // const wrapper

std::cout << cv->at(0) << '\n'; // okay at() is a const method

cv->push_back(8); // ILLEGAL!! push_back() is not a const method

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM