mirror of
https://gitlab.com/fbb-git/cppannotations
synced 2024-09-28 03:20:44 +02:00
ready for 12.3.0
This commit is contained in:
parent
b075c82f0c
commit
d231922245
13 changed files with 239 additions and 27 deletions
|
@ -1,15 +1,20 @@
|
|||
C++-annotations (12.3.0) WIP
|
||||
C++-annotations (12.3.0)
|
||||
|
||||
* removed section 'Returning types nested under class templates'
|
||||
(advancedtemplates/returnnested), sf since C++20
|
||||
* added descriptions of the back_, front_ and inside insert_iterator
|
||||
functions to the STL chapter.
|
||||
* updated the Generic Algorithm chapter: merged the descriptions of very
|
||||
similar algorithms (like 'copy' and 'copy_if'), added the descriptions
|
||||
of several new algorithms, added a section about execution policies and
|
||||
updated the descriptions of generic algorithms supporting execution
|
||||
policies.
|
||||
policies. Added a new section about handling raw memory.
|
||||
* the memory chapter's section about 'placement new' contains a forward link
|
||||
to the STL section about initializing raw memory.
|
||||
* repaired typos
|
||||
* during the 2022-2023 Academic Year many typo reports and suggestions for
|
||||
updating sections were submitted by the C++ course participants Jeroen
|
||||
Lammersma (jeroen at lammersma dot dev) and Channa Dias Perera (c dot dias
|
||||
dot perera at student dot rug dot nl: thanks, gentlemen, for your valuable
|
||||
contributions!
|
||||
|
||||
|
||||
C++-annotations (12.2.0)
|
||||
|
|
|
@ -39,6 +39,8 @@ IFDEF(latex)(latexcommand(
|
|||
\pagestyle{headings}
|
||||
\pagenumbering{arabic}))()
|
||||
|
||||
COMMENT(WIP
|
||||
|
||||
COMMENT( 1 )
|
||||
lchapter(Overview)(Overview Of The Chapters)
|
||||
includefile(overview)
|
||||
|
@ -111,10 +113,14 @@ COMMENT( 18 )
|
|||
lchapter(STL)(The Standard Template Library)
|
||||
includefile(stl)
|
||||
|
||||
END WIP)
|
||||
|
||||
COMMENT( 19 )
|
||||
lchapter(GENERIC)(The STL Generic Algorithms)
|
||||
includefile(generic)
|
||||
|
||||
COMMENT(WIP
|
||||
|
||||
COMMENT( 20 )
|
||||
lchapter(THREADING)(Multi Threading)
|
||||
includefile(threading)
|
||||
|
@ -139,5 +145,7 @@ COMMENT( 25 )
|
|||
lchapter(CONCRETE)(Concrete Examples)
|
||||
includefile(concrete)
|
||||
|
||||
END WIP)
|
||||
|
||||
IFDEF(latex)(latexcommand(\cleardoublepage\phantomsection\printindex))()
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ includefile(generic/intro)
|
|||
includefile(generic/allof)
|
||||
|
||||
lsubsect(BEGEND)(begin / end)
|
||||
includefile(generic/begin)
|
||||
includefile(generic/beginend)
|
||||
|
||||
lsubsect(BINSRCH)(binary_search)
|
||||
includefile(generic/binarysearch)
|
||||
|
@ -172,23 +172,9 @@ includefile(generic/intro)
|
|||
lsubsect(TRANSRED)(transform_reduce)
|
||||
includefile(generic/transformreduce)
|
||||
|
||||
COMMENT(
|
||||
mention:
|
||||
|
||||
unititialized_copy, unititialized_copy_n unititialized_fill,
|
||||
unititialized_fill_n unititialized_move unititialized_move_n
|
||||
at the non-init functions
|
||||
|
||||
separate sections:
|
||||
|
||||
uninitialized_default_construct(_n)
|
||||
uninitialized_value_construct(_n)
|
||||
destroy(_n/_at)
|
||||
construct_at
|
||||
)
|
||||
|
||||
------------
|
||||
|
||||
lsubsect(UNINIT)(handling uninitialized memory)
|
||||
includefile(generic/uninitialized)
|
||||
|
||||
lsubsect(UNIQUE)(unique)
|
||||
includefile(generic/unique)
|
||||
|
||||
|
|
26
annotations/yo/generic/examples/uninitialized.cc
Normal file
26
annotations/yo/generic/examples/uninitialized.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
int main()
|
||||
{
|
||||
char raw[4 * sizeof(string)]; // raw memory to receive strings
|
||||
string *ptr = reinterpret_cast<string *>(raw); // pointer to strings
|
||||
|
||||
// construct 4 strings in raw
|
||||
uninitialized_default_construct_n(ptr, 4);
|
||||
destroy(ptr, ptr + 4); // call the strings' destructors
|
||||
|
||||
vector<string> vs(4, "string"); // move 4 strings to raw memory
|
||||
uninitialized_move(vs.begin(), vs.end(), ptr);
|
||||
|
||||
cout << vs.front() << ", " << vs.back() << '\n' <<
|
||||
ptr[0] << ", " << ptr[3] << '\n';
|
||||
|
||||
destroy(ptr, ptr + 4); // call the strings' destructors
|
||||
}
|
||||
// Displays:
|
||||
// ,
|
||||
// string, string
|
|
@ -85,7 +85,7 @@ The annotations() distinguishes the following categories
|
|||
link(copy)(COPY);
|
||||
link(copy_backward)(COPYBACK);
|
||||
link(copy_if)(COPY);
|
||||
link(move; move_backward)(MOVE);
|
||||
link(move; move_backward)(MOVEFWD);
|
||||
link(partition_copy)(PARTCP);
|
||||
link(partial_sort_copy)(PARTSORT);
|
||||
link(remove_copy; remove_copy_if)(REMOVE);
|
||||
|
@ -93,7 +93,7 @@ The annotations() distinguishes the following categories
|
|||
link(reverse_copy)(REVERSE);
|
||||
link(rotate_copy)(ROTATE);
|
||||
link(sample)(SAMPLE);
|
||||
link(shift_left; shift_right)(MOVE);
|
||||
link(shift_left; shift_right)(MOVEFWD);
|
||||
link(unique_copy)(UNIQUECP);
|
||||
)
|
||||
it() Counters: performing count operations:
|
||||
|
@ -112,6 +112,7 @@ The annotations() distinguishes the following categories
|
|||
link(fill; fill_n)(FILL);
|
||||
link(generate; generate_n)(GEN);
|
||||
link(iota)(IOTA);
|
||||
link(uninitialized (raw) memory)(UNINIT);
|
||||
)
|
||||
it() Limiters: determining boundaries of data:
|
||||
quote(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
hi(move) hi(move_backward)
|
||||
hi(move) hi(move_backward) hi(shift_left) hi(shift_right)
|
||||
itemization(
|
||||
it() Header file: tt(<algorithm>)
|
||||
it() Function prototype:
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
)
|
||||
it() Description:
|
||||
This algorithm acts like tt(accumulate)
|
||||
(cf. link(accumulate)(ACCUMULATE)), but the algorithm requires that the used
|
||||
(cf. link(accumulate)(ACCU)), but the algorithm requires that the used
|
||||
operator is both associative and commutative: regrouping and rearranging the
|
||||
elements in any order may not affect the final outcome. E.g., the numeric
|
||||
addition operator satisfies both requirements.
|
||||
|
|
115
annotations/yo/generic/uninitialized.yo
Normal file
115
annotations/yo/generic/uninitialized.yo
Normal file
|
@ -0,0 +1,115 @@
|
|||
Section ref(PLACEMENT) covers the placement new operator. The placement new
|
||||
operator is used to install values or objects in 'raw memory', i.e., memory
|
||||
that is already available, but hasn't yet been initialized for the intended
|
||||
object types.
|
||||
|
||||
As covered before, when calling something like tt(auto ptr = new string{
|
||||
"hello" }) the string is constructed in memory specifically allocated to
|
||||
contain the object, and the object type's constructor initializes the object
|
||||
in that memory. Likewise, when calling tt(delete ptr) the string's destructor
|
||||
is called, followed by returning the memory allocated by tt(new) to the common
|
||||
pool.
|
||||
|
||||
When using placement new the memory to contain the object is already
|
||||
available, and the construction tt(auto ptr = new (storageAddress) string{
|
||||
"hello" }) is used to merely construct the string at the location specified by
|
||||
tt(storageAddress). That string can then (as usual) be accessed via tt(ptr),
|
||||
but tt(delete ptr) cannot be used, since the memory at tt(storageAddress) was
|
||||
already available before invoking the placement new operator. Therefore, in
|
||||
these cases the remarkable situation is encountered where the object's
|
||||
destructor must explicitly be called (using tt(ptr->~string())) and using
|
||||
tt(delete ptr) is completely wrong, causing a memory error which aborts the
|
||||
program.
|
||||
|
||||
Several generic algorithms, all supporting execution policies, are available
|
||||
simplifying the use of tt(placement new). To use these algorithm the
|
||||
tthi(memory) header file must be included.
|
||||
|
||||
hi(placement new: generic algorithms)hi(uninitialized... algorithms)
|
||||
Facilities are available to copy, fill, initialize, and move objects to/in
|
||||
uninitialized (raw) memory, as well as facilities to delete the objects stored
|
||||
in raw memory. Here is an overvieuw of the available facilities (cf.
|
||||
url(cppreference)(https://en.cppreference.com) for more details
|
||||
about the algorithms handling uninitialized memory):
|
||||
itemization(
|
||||
itt(uninitialized_copy([ExecPol,]
|
||||
ForwardIterator first, ForwardIterator last,
|
||||
ForwardIterator dest);)nl()
|
||||
copies the elements in the rangett(first, last) to the raw memory
|
||||
starting at tt(dest), returning the location beyond the last copied
|
||||
element.
|
||||
itt(uninitialized_copy_n([ExecPol,]
|
||||
ForwardIterator first, size_t nObjects,
|
||||
ForwardIterator dest);)nl()
|
||||
same as the previous algorithm, but copies tt(nObjects).
|
||||
itt(uninitialized_default_construct([ExecPol,]
|
||||
ForwardIterator first, ForwardIterator last);)nl()
|
||||
installs default constructed values at the raw memory locations reached
|
||||
by the iterator range rangett(first, last). The algorithm requires
|
||||
that the types referred to by the iterators are either trivial types
|
||||
(like built-in types) or define tt(value_type) returning their type
|
||||
names. When using trivial types the installed do not assume that the
|
||||
installed values are 0-initialized.
|
||||
itt(uninitialized_default_construct_n([ExecPol,]
|
||||
ForwardIterator first, size_t nObjects);)nl()
|
||||
same as the previous algorithm, but installs tt(nObjects) in the
|
||||
uninitialized memory.
|
||||
itt(uninitialized_fill([ExecPol,]
|
||||
ForwardIterator first, ForwardIterator last,
|
||||
Type const &value);)nl()
|
||||
like the first algorithm, but installing copies of tt(value) in the
|
||||
uninitialized memory.
|
||||
itt(uninitialized_fill([ExecPol,]
|
||||
ForwardIterator first, size_t nObjects,Type const &value);)nl()
|
||||
same as the previous algorithm, but copies tt(value) to the
|
||||
tt(nObjects) subsequent locations in the uninitialized memory.
|
||||
itt( uninitialized_move([ExecPol,]
|
||||
ForwardIterator first, ForwardIterator last,
|
||||
ForwardIterator dest);)nl()
|
||||
same as the first algorithm, but the elements in the rangett(first,
|
||||
last) are moved to the raw memory.
|
||||
itt(uninitialized_move_n([ExecPol,]
|
||||
ForwardIterator first, size_t nObjects,
|
||||
ForwardIterator dest);)nl()
|
||||
same as the previous algorithm, but tt(nObjects) are moved.
|
||||
itt(uninitialized_value_construct([ExecPol,]
|
||||
ForwardIterator first, ForwardIterator last);)nl()
|
||||
same as tt(uninitialized_default_construct), but requires that the
|
||||
types referred to by the iterators define tt(value_type) returning
|
||||
their type names.
|
||||
itt(uninitialized_value_construct_n([ExecPol,]
|
||||
ForwardIterator first, size_t nObjects);)nl()
|
||||
same as the previous algorithm, but installs tt(nObjects) in the
|
||||
uninitialized memory.
|
||||
)
|
||||
|
||||
The algorithm hi(construct_at) tt(Type *construct_at(Type *raw, Args
|
||||
&&...args)) constructs an object of type tt(Type) in the raw memory at
|
||||
tt(raw), passing tt(args...) to tt(Type's) constructor.
|
||||
|
||||
To delete the objects installed in raw memory the following facilities are
|
||||
available:
|
||||
itemization(
|
||||
itt(void destroy([ExecPol,] ForwardIterator first,
|
||||
ForwardIterator last);)nl()
|
||||
assuming the the types to which tt(first) refers: it calls
|
||||
tt(iterator->~Type()) for all elements in the range rangett(first,
|
||||
last).
|
||||
itt(void destroy([ExecPol,] ForwardIterator first, size_t nObjects);)nl()
|
||||
same as the previous algorithm, but calls the destructors of
|
||||
tt(nObjects) objects.
|
||||
itt(void destroy_at(Type *raw);)nl()
|
||||
calls the destructor of the object installed at tt(raw) using placement
|
||||
new. If the tt(raw) pointer points to an array of placement new
|
||||
allocated objects then the destructors of the elements of the array
|
||||
are called.
|
||||
)
|
||||
|
||||
Here is an example:
|
||||
verbinclude(-as4 examples/uninitialized.cc)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -98,3 +98,6 @@ placement tt(new) in combination with a statically allocated
|
|||
buffer all the objects' destructors must be called explicitly, as in the
|
||||
following example:
|
||||
verbinclude(//CODE examples/placement2.cc)
|
||||
|
||||
Several standard template library functions are available for handling
|
||||
unitialized (raw) memory. See section ref(UNINIT) for a description.
|
||||
|
|
|
@ -33,12 +33,16 @@ includefile(threading/mutex)
|
|||
lsect(LOCKS)(Locks and lock handling)
|
||||
includefile(threading/locks)
|
||||
|
||||
subsect(Deadlocks)
|
||||
lsubsect(DEADLOCKS)(Deadlocks)
|
||||
includefile(threading/deadlocks)
|
||||
|
||||
subsect(Shared locks)
|
||||
includefile(threading/sharedlock)
|
||||
|
||||
subsect(Scoped locks)
|
||||
includefile(threading/scopedlock)
|
||||
|
||||
|
||||
sect(Event handling (condition variables))
|
||||
includefile(threading/events)
|
||||
|
||||
|
|
41
annotations/yo/threading/examples/scopedlock.cc
Normal file
41
annotations/yo/threading/examples/scopedlock.cc
Normal file
|
@ -0,0 +1,41 @@
|
|||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
//code
|
||||
int value;
|
||||
mutex valueMutex;
|
||||
mutex coutMutex;
|
||||
|
||||
void fun1()
|
||||
{
|
||||
scoped_lock sl{ coutMutex, valueMutex };
|
||||
cout << "fun 1 locks cout\n";
|
||||
sleep(1);
|
||||
cout << "fun 1 locks value\n";
|
||||
}
|
||||
|
||||
void fun2()
|
||||
{
|
||||
scoped_lock sl{ valueMutex, coutMutex };
|
||||
cout << "fun 2 locks value\n";
|
||||
sleep(1);
|
||||
cout << "fun 2 locks cout\n";
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
thread t1(fun1);
|
||||
fun2();
|
||||
t1.join();
|
||||
}
|
||||
// Displays:
|
||||
// fun 2 locks value
|
||||
// fun 2 locks cout
|
||||
// fun 1 locks cout
|
||||
// fun 1 locks value
|
||||
//=
|
||||
|
19
annotations/yo/threading/scopedlock.yo
Normal file
19
annotations/yo/threading/scopedlock.yo
Normal file
|
@ -0,0 +1,19 @@
|
|||
Deadlocks can be avoided using the principles described in the previous
|
||||
section. However, instead of placing the responsibility for avoiding deadlocks
|
||||
on the shoulders of the software engineer, an alternative approach is
|
||||
available: a ti(scoped_lock) can be used to lock multiple semaphores at once,
|
||||
where the tt(scoped_lock) ensures that deadlocks are avoided.
|
||||
|
||||
The tt(scoped_lock) also has a default constructor, performing no actions, so
|
||||
it's up to the software engineer to define tt(scoped_lock) objects with at
|
||||
least one tt(mutex). Before using tt(scoped_lock) objects the tthi(mutex)
|
||||
header file must be included. Adapting the example from section
|
||||
ref(DEADLOCKS): both functions define a tt(scoped_lock) (note that the order
|
||||
in which the mutexes are specified isn't relevant), and deadlocks are do not
|
||||
occur:
|
||||
verbinclude(-ns4 //code examples/lock.cc)
|
||||
|
||||
Thus, instead of using tt(lock_guard) objects, tt(scoped_lock) objects can be
|
||||
used. It's a matter of taste whether tt(lock_guards) or tt(scoped_locks)
|
||||
should be preferred when only one mutex is used. Maybe tt(scoped_lock) should
|
||||
be preferred, since it always works....
|
|
@ -3,6 +3,10 @@ changes (and occasionally also for the third field of the version number). At
|
|||
a major version upgrade the entries of the previous major version are kept,
|
||||
and entries referring to older releases are removed.
|
||||
itemization(
|
||||
it() Version 12.3.0 updates and reorganizes the coverage of the generic
|
||||
algorithms, fixes many typos and unclarities in the Annotations' text,
|
||||
removed superfluous sections since C++20, and adds an overview of
|
||||
facilities to handle objects constructed in raw memory.
|
||||
it() Version 12.2.0 takes into account that tt(std::iterator) is
|
||||
deprecated. Section ref(ITERATORCONS) was rewritten; section
|
||||
ref(OPERATORINDEX) was updated (tt(operator[] const) should return
|
||||
|
|
Loading…
Reference in a new issue