Using non-default constructors with new[] now thread-safe

This commit is contained in:
Frank B. Brokken 2016-11-24 12:50:02 +01:00
parent 2ccbf47641
commit b2246171c6
3 changed files with 19 additions and 19 deletions

View file

@ -21,6 +21,9 @@
* Added a section about folding expressions to the Class Templates chapter.
* The section about using non-default constructors now contains thread-safe
examples.
* Fixed several typos.
C++-annotations (10.6.0)

View file

@ -8,7 +8,7 @@ using namespace std;
string *nStrings(size_t size, char const *fname)
{
static ifstream in;
static thread_local ifstream in;
struct Xstr: public string
{

View file

@ -79,28 +79,25 @@ initializers even though no tt(Xstr) object is available by that time.
When this program is run, it displays the first 10 lines of the file
tt(nstrings.cc).
Note that the above implementation can't safely be used in a multithreaded
environment. In that case a emi(mutex) should be used to protect the three
statements just before the function's return statement.
Note that the example defines a tt(static thread_local ifstream)
object. Thread_local variables are formally introduced in chapter
ref(THREADING). The tt(thread_local) specification assures that the function
can safely be used, even in multithreaded programs.
A completely different way to avoid the double initialization (not using
inheritance) is to use placement new (cf. section ref(PLACEMENT)): simply
allocate the required amount of memory followed by the proper in-place
allocation of the objects, using the appropriate constructors. The following
example can also be used in multithreaded environments. The approach uses a
pair of static tt(construct/destroy) members to perform the required
initialization.
In the program shown below tt(construct) expects a tt(istream) that
provides the initialization strings for objects of a class tt(String) simply
containing a tt(std::string) object. tt(Construct) first allocates enough
memory for the tt(n) tt(String) objects plus room for an initial tt(size_t)
value. This initial tt(size_t) value is then initialized with tt(n). Next, in
a tt(for) statement, lines are read from the provided stream and the lines are
passed to the constructors, using placement new calls. Finally the address of
the first tt(String) object is returned.
The member tt(destroy) handles the destruction of the objects. It
allocation of the objects, using the appropriate constructors. In the next
example a pair of static tt(construct/destroy) members are used to perform the
required initialization. In the example tt(construct) expects an tt(istream)
that provides the initialization strings for objects of a class tt(String)
simply containing a tt(std::string) object. tt(Construct) first allocates
enough memory for the tt(n) tt(String) objects plus room for an initial
tt(size_t) value. This initial tt(size_t) value is then initialized with
tt(n). Next, in a tt(for) statement, lines are read from the provided stream
and the lines are passed to the constructors, using placement new
calls. Finally the address of the first tt(String) object is returned. Then,
the destruction of the objects is handled by the member tt(destroy). It
retrieves the number of objects to destroy from the tt(size_t) it finds just
before the location of the address of the first object to destroy. The objects
are then destroyed by explicitly calling their destructors. Finally the raw