/***************************************************************************
Lazy<T>: template class for lazy initialization of objects whose
values do not change after initialization.
In a multi-threaded environment, this makes use of "double checked locking"
for an efficient, thread-safe solution.
Usage:
Lazy<T> obj; // declaration of the lazy object
...
do {
Lazy<T>::Builder builder(obj);
if (!builder()) break; // if we are not building, the break out
UniquePtr<T> p; // create a pointer
...
builder.move(p); // move p into the object to complete the initialization
// We can then complete the initialization process.
} while(0); // When this scope closes, the object is fully initialized.
// subsequent attempts to build the object will yield
// !builder.built()
T objCopy = *obj; // *obj returns a read-only reference
// one can also use -> operator
It is important to follow this recipe carefully. In particular,
the builder must be enclosed in a scope, as it's destructor
plays a crucial role in finalizing the initialization.
NOTE: if p is null in builder.move(p), the object is still considered
built.
****************************************************************************/
template<class T, class P=DefaultDeleterPolicy>
class Lazy {
public:
Lazy();
Lazy(const Lazy&);
Lazy& operator=(const Lazy&);
// deep copies using T's copy constructor
// EXCEPTIONS: may throw (but provides strong ES guarantee)
const T& operator*() const; // pointer access
const T* operator->() const;
const T* get() const;
operator fake_null_type() const;
// allows test against 0
~Lazy();
kill(); // destroy and reset
bool built() const; // test if already built
class Builder {
Builder(const Lazy&);
~Builder()
bool operator()() const; // test if we are building
void move(UniquePtr<T,P>&);
// EXCEPTIONS: may throw an exception if the move is not allowed
// (i.e., not building or already moved).
// Provides strong ES guarantee.
};
};
// EXCEPTIONS: except where noted, no exceptions are thrown
// NOTE: For more on double-checked locking, see
// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
// NOTE: when compiled with the NTL_THREADS option, the Lazy
// class may contain data members from the standard library
// that may not satisfy the requirements of the Vec class
// (i.e., relocatability). One can wrap it in a pointer
// class (e.g., CopiedPtr) to deal with this.
// NOTE: The optional parameter P is used as in the specification
// of the UniquePtr class. The default should work fine in
// most cases. It was introduced mainly to allow for the PIMPL
// paradigm.