mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-11-16 07:48:44 +01:00
Using non-default constructors with new[] now thread-safe
This commit is contained in:
parent
2ccbf47641
commit
b2246171c6
3 changed files with 19 additions and 19 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue