Безопасно ли в этом коде реализована идиома двойной проверки с использованием C ++ 11 atomi c? Я видел в "Языке программирования C ++ 4-е изд." пример, который использует atomic<bool>
, и я сделал все возможное, чтобы все было эквивалентно, но я не уверен. Кроме того, можно ли это улучшить?
Я бы хотел избежать call_once
из-за нехватки памяти once_flag
.
Этот "LazyArray" был написан как попытка сокращения памяти заменить массивы минимальными изменениями в клиентском коде (ожидается доступ к небольшому подмножеству элементов). Доступ к массиву из нескольких потоков является фактом жизни, и в целом блокировка будет проблематичной c из-за производительности.
/**
* Lazy creation of array elements.
* They will only be created when they are referenced.
*
* This "array" does not support iteration because it can have holes
*
* Array bounds isn't checked to keep it fast.
* Destruction of the array destroys all the T objects (via the unique_ptr d'tor)
*/
template<class T, size_t size>
class LazyArray
{
typedef LazyArray<T, size> mytype;
public:
// copying is not allowed (unlike regular arrays)
LazyArray(const LazyArray&) = delete;
LazyArray& operator=(const LazyArray&) = delete;
LazyArray(){}
T& operator[](size_t i)
{
return at(i);
}
const T& operator[](size_t i) const
{
return const_cast<mytype *>(this)->at(i);
}
private:
using guard = std::lock_guard<std::mutex>;
// get T object at index i by reference
T& at(size_t i) // only non-const variant is implemented, const version will use const_cast
{
auto &p = m_array[i];
std::atomic<T*> ap(p.get());
if(!ap) // object not created yet
{
guard g(mtx);
ap = p.get();
if(!ap)
p.reset(new T);
}
return *p;
}
std::unique_ptr<T> m_array[size];
std::mutex mtx;
};