[英]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 ++。
所以我要求你幫助解決我的問題。 任何建議或提示來解決這個問題將不勝感激!
謝謝
我的主要目標是使我的包裝容器類型獨立,因此它可以“鎖定”和“解鎖”它所持有的容器的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.