From b2246171c66b848268300a93710deda50c55861e Mon Sep 17 00:00:00 2001 From: "Frank B. Brokken" Date: Thu, 24 Nov 2016 12:50:02 +0100 Subject: [PATCH] Using non-default constructors with new[] now thread-safe --- annotations/changelog | 3 ++ .../yo/inheritance/examples/nstrings.cc | 2 +- annotations/yo/inheritance/nondefault.yo | 33 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/annotations/changelog b/annotations/changelog index 584e2ebc..143596f2 100644 --- a/annotations/changelog +++ b/annotations/changelog @@ -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) diff --git a/annotations/yo/inheritance/examples/nstrings.cc b/annotations/yo/inheritance/examples/nstrings.cc index c9575fe2..f4906d73 100644 --- a/annotations/yo/inheritance/examples/nstrings.cc +++ b/annotations/yo/inheritance/examples/nstrings.cc @@ -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 { diff --git a/annotations/yo/inheritance/nondefault.yo b/annotations/yo/inheritance/nondefault.yo index 752b90cc..79ca32a9 100644 --- a/annotations/yo/inheritance/nondefault.yo +++ b/annotations/yo/inheritance/nondefault.yo @@ -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