更多 C++ 慣用法/寫時複製
外觀
實現延遲複製最佳化。就像延遲初始化一樣,只在需要的時候才執行操作,以提高效率。
- COW (寫時複製)
- 延遲複製
複製物件有時會導致效能下降。如果物件經常被複制,但在以後很少被修改,寫時複製可以提供顯著的最佳化。為了實現寫時複製,一個指向實際內容的智慧指標用於封裝物件的價值,並且在每次修改時,都會檢查物件的引用計數;如果物件被引用多次,則會在修改之前建立內容的副本。
#ifndef COWPTR_HPP
#define COWPTR_HPP
#include <memory>
template <class T>
class CowPtr
{
public:
typedef std::shared_ptr<T> RefPtr;
private:
RefPtr m_sp;
void detach()
{
T* tmp = m_sp.get();
if( !( tmp == 0 || m_sp.unique() ) ) {
m_sp = RefPtr( new T( *tmp ) );
}
}
public:
CowPtr(T* t)
: m_sp(t)
{}
CowPtr(const RefPtr& refptr)
: m_sp(refptr)
{}
const T& operator*() const
{
return *m_sp;
}
T& operator*()
{
detach();
return *m_sp;
}
const T* operator->() const
{
return m_sp.operator->();
}
T* operator->()
{
detach();
return m_sp.operator->();
}
};
#endif
這種寫時複製的實現是通用的,但除了必須透過智慧指標解除引用來引用內部物件的不便之外,它至少有一個缺點:那些返回對其內部狀態引用的類,比如
char & String::operator[](int)
可能會導致意想不到的行為。[1]
考慮以下程式碼片段
CowPtr<String> s1 = "Hello";
char &c = s1->operator[](4); // Non-const detachment does nothing here
CowPtr<String> s2(s1); // Lazy-copy, shared state
c = '!'; // Uh-oh
最後一行程式碼的目的是修改原始字串s1,而不是副本,但作為副作用,s2也意外被修改了。
一個更好的方法是編寫一個自定義的寫時複製實現,該實現封裝在我們想要延遲複製的類中,對使用者來說是透明的。為了解決上述問題,可以將那些已經將內部狀態的引用傳遞出去的物件標記為“不可共享”——換句話說,強制複製操作深度複製物件。作為最佳化,可以在任何不傳遞內部狀態引用(例如,void string::clear())的非常量操作之後將物件恢復為“可共享”,因為客戶端程式碼期望這些引用會被無效化。[1]
- 活動模板庫
- 許多 Qt 類 (隱式共享)