Шаблон LazyArray через std :: unique_ptr, это правильная реализация идиомы двойной проверки? - PullRequest
1 голос
/ 16 марта 2020

Безопасно ли в этом коде реализована идиома двойной проверки с использованием 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;
};


...