cos, sin, tan etc. are to be usedaccepting arguments in degrees rather than arguments inradians. Unfortunately, the function namecos is already in use, and thatfunction accepts radians as its arguments, rather than degrees.Problems like these are usually solved by defining another name, e.g., thefunction namecosDegrees is defined.C++ offers an alternativesolution throughnamespaces. Namespaces can be considered asareas or regions in the code in which identifiers may be defined. Identifiersdefined in a namespace normally won't conflict with names already definedelsewhere (i.e., outside of their namespaces). So, a functioncos(expecting angles in degrees) could be defined in a namespaceDegrees. When callingcos from withinDegrees you would call thecos function expecting degrees, rather than the standardcos functionexpecting radians.
namespace identifier { // declared or defined entities // (declarative region) }The identifier used when defining a namespace is a standardC++identifier.
Within thedeclarative region, introduced in the above code example,functions, variables, structs, classes and even (nested) namespaces can bedefined or declared. Namespaces cannot be defined within a functionbody. However, it is possible to define a namespace using multiplenamespace declarations. Namespaces are `open' meaning thata namespaceCppAnnotations could be defined in a filefile1.cc andalso in a filefile2.cc. Entities defined in theCppAnnotationsnamespace of filesfile1.cc andfile2.cc are then united in oneCppAnnotations namespace region. For example:
// in file1.cc namespace CppAnnotations { double cos(double argInDegrees) { ... } } // in file2.cc namespace CppAnnotations { double sin(double argInDegrees) { ... } }Bothsin andcos are now defined in the sameCppAnnotations namespace.
Namespace entities can be defined outside of their namespaces. Thistopic is discussed in section4.1.4.1.
namespace CppAnnotations { double cos(double degrees); double sin(double degrees); }Entities defined in the anonymous namespace are comparable toC'sstatic functions and variables. InC++ thestatic keyword canstill be used, but its preferred use is inclass definitions (seechapter7). In situations where inC static variables orfunctions would have been used the anonymous namespace should be used inC++.
The anonymous namespace is a closed namespace: it is notpossible to add entities to the same anonymous namespace using differentsource files.
cos()defined in theCppAnnotations namespace may be used as follows: // assume CppAnnotations namespace is declared in the // following header file: #include <cppannotations> int main() { cout << "The cosine of 60 degrees is: " << CppAnnotations::cos(60) << '\n'; }This is a rather cumbersome way to refer to thecos() function in theCppAnnotations namespace, especially so if the function is frequentlyused. In cases like these anabbreviated form can beused after specifying ausing declaration. Following
using CppAnnotations::cos; // note: no function prototype, // just the name of the entity // is required.
callingcos results in a call of thecos function defined in theCppAnnotations namespace. This implies that the standardcosfunction, accepting radians, is not automatically called anymore. To call thatlattercos function the plainscope resolution operator should be used:
int main() { using CppAnnotations::cos; ... cout << cos(60) // calls CppAnnotations::cos() << ::cos(1.5) // call the standard cos() function << '\n'; }Ausing declaration can have restricted scope. It can be used inside ablock. Theusing declaration prevents the definition of entities havingthe same name as the one used in theusing declaration. It is not possibleto specify ausing declaration for a variablevalue in some namespace,and to define (or declare) an identically named object in a block alsocontaining ausing declaration. Example:
int main() { using CppAnnotations::value; ... cout << value << '\n'; // uses CppAnnotations::value int value; // error: value already declared. }using declaration is theusing directive:using namespace CppAnnotations;
Following this directive,all entities defined in theCppAnnotations namespace are used as if they were declared byusingdeclarations.
While theusing directive is a quick way to import all the names of a namespace (assumingthe namespace has previously been declared or defined), it is at the same timea somewhat dirty way to do so, as it is less clear what entity is actuallyused in a particular block of code.
If, e.g.,cos is defined in theCppAnnotations namespace,CppAnnotations::cos is going to be used whencos is called. However,ifcos isnot defined in theCppAnnotations namespace, thestandardcos function will be used. Theusing directive does notdocument as clearly as theusing declaration what entity will actually beused. Therefore use caution when applying theusing directive.
Namespace declarations are context sensitive: when ausing namespacedeclaration is specified inside a compound statement then the declaration isvalid until the compound statement's closing curly brace has beenencountered. In the next example a stringfirst is defined withoutexplicit specifyingstd::string, but once the compound statement has endedthe scope of theusing namespace std declaration has also ended, and sostd:: is required once again when definingsecond:
#include <string> int main() { { using namespace std; string first; } std::string second; }Ausing namespace directive cannot be used within thedeclaration block of a class- or enumeration-type. E.g., the following examplewon't compile:
struct Namespace { using namespace std; // won't compile };`Koenig lookup' refers to the fact that if a function is called withoutspecifying its namespace, then the namespaces of its argument types are usedto determine the function's namespace. If the namespace in which the argumenttypes are defined contains such a function, then that function is used. Thisprocedure is called the `Koenig lookup'.
As an illustration consider the next example. The functionFBB::fun(FBB::Value v) is defined in theFBB namespace. Itcan be called without explicitly mentioning its namespace:
#include <iostream> namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "fun called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // Koenig lookup: no namespace // for fun() specified } /* generated output: fun called for 0 */ The compiler is rather smart when handling namespaces. IfValue in thenamespace FBB would have been defined asusing Value = int thenFBB::Value would be recognized asint, thus causing the Koenig lookupto fail.As another example, consider the next program. Here two namespaces areinvolved, each defining their ownfun function. There is noambiguity, since the argument defines the namespace andFBB::fun iscalled:
#include <iostream> namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "FBB::fun() called for " << x << '\n'; } } namespace ES { void fun(FBB::Value x) { std::cout << "ES::fun() called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // No ambiguity: argument determines // the namespace } /* generated output: FBB::fun() called for 0 */Here is an example in which thereis an ambiguity:fun has twoarguments, one from each namespace. The ambiguity must be resolved by theprogrammer:
#include <iostream> namespace ES { enum Value // defines ES::Value { FIRST }; } namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x, ES::Value y) { std::cout << "FBB::fun() called\n"; } } namespace ES { void fun(FBB::Value x, Value y) { std::cout << "ES::fun() called\n"; } } int main() { // fun(FBB::FIRST, ES::FIRST); ambiguity: resolved by // explicitly mentioning // the namespace ES::fun(FBB::FIRST, ES::FIRST); } /* generated output: ES::fun() called */An interesting subtlety with namespaces is that definitions in onenamespace may break the code defined in another namespace. It shows thatnamespaces may affect each other and that namespaces may backfire if we're notaware of their peculiarities. Consider the following example:
namespace FBB { struct Value {}; void fun(int x); void gun(Value x); } namespace ES { void fun(int x) { fun(x); } void gun(FBB::Value x) { gun(x); } } Whatever happens, the programmer'd better not use any of the functionsdefined in theES namespace, since that would result in infiniterecursion. However, that's not the point. The point is that the programmerwon't even be given the opportunity to callES::fun since the compilationfails.Compilation fails forgun but not forfun. But why is that so? WhyisES::fun flawlessly compiling whileES::gun isn't? InES::funfun(x) is called. Asx's type is not defined in a namespace the Koeniglookup does not apply andfun calls itself with infinite recursion.
WithES::gun the argument is defined in theFBBnamespace. Consequently, theFBB::gun function is a possible candidate tobe called. ButES::gun itself also is possible asES::gun's prototypeperfectly matches the callgun(x).
Now consider the situation whereFBB::gun has not yet beendeclared. Then there is of course no ambiguity. The programmer responsible fortheES namespace is resting happily. Some time after that the programmerwho's maintaining theFBB namespace decides it may be nice to add afunctiongun(Value x) to theFBB namespace. Now suddenly the code inthe namespaceES breaks because of an addition in a completely othernamespace (FBB). Namespaces clearly are not completely independent of eachother and we should be aware of subtleties like the above. Later in theC++ Annotations (chapter11) we'll return to this issue.
Koenig lookup is only used in the context of namespaces. If a functionis defined outside of a namespace, defining a parameter of a type that'sdefined inside a namespace, and that namespace also defines a function with anidentical signature, then the compiler reports an ambiguity when that functionis called. Here is an example, assuming the abovementioned namespaceFBBis also available:
void gun(FBB::Value x); int main(int argc, char **argv) { gun(FBB::Value{}); // ambiguity: FBB::gun and ::gun can both // be called. }std namespace is reserved byC++. The standard defines manyentities that are part of the runtime available software (e.g.,cout, cin,cerr); the templates defined in theStandard Template Library (cf.chapter18); and theGeneric Algorithms (cf. chapter19)are defined in thestd namespace.Regarding the discussion in the previous section,usingdeclarations may be used when referring to entities in thestd namespace.For example, to use thestd::coutstream, the code may declare this object as follows:
#include <iostream> using std::cout;
Often, however, the identifiers defined in thestd namespace can allbe accepted without much thought. Because of that, one frequently encounters ausing directive, allowing the programmer to omit a namespace prefix whenreferring to any of the entities defined in the namespace specified with theusing directive. Instead of specifyingusing declarations thefollowingusing directive is frequently encountered:construction like
#include <iostream> using namespace std;
Should ausing directive, rather thanusing declarations be used?As arule of thumb one might decide to stick tousing declarations, upto the point where the list becomes impractically long, at which point ausing directive could be considered.
Two restrictions apply tousing directives anddeclarations:
namespace std. This isnot compiler enforced but is imposed upon usercode by the standard;Using declarations and directives should not be imposed uponcode written by third parties. In practice this means thatusingdirectives and declarations should be banned from header files and should onlybe used in source files (cf. section7.11.1). namespace CppAnnotations { int value; namespace Virtual { void *pointer; } }The variablevalue is defined in theCppAnnotationsnamespace. Within theCppAnnotations namespace another namespace(Virtual) is nested. Within that latter namespace the variablepointer is defined. To refer to thesevariable the following options are available:
int main(){ CppAnnotations::value = 0; CppAnnotations::Virtual::pointer = 0;}using namespace CppAnnotations directive can be provided. Nowvalue can be used without any prefix, butpointer must be used with theVirtual:: prefix:using namespace CppAnnotations;int main(){ value = 0; Virtual::pointer = 0;}using namespace directive for the full namespace chain can be used. Nowvalue needs itsCppAnnotations prefix again, butpointer doesn't require a prefix anymore:using namespace CppAnnotations::Virtual;int main(){ CppAnnotations::value = 0; pointer = 0;}using namespace directives none of the namespace prefixes are required anymore:using namespace CppAnnotations;using namespace Virtual;int main(){ value = 0; pointer = 0;}using declarations:using CppAnnotations::value;using CppAnnotations::Virtual::pointer;int main(){ value = 0; pointer = 0;}using namespace directives andusing declarations can also be used. E.g., ausing namespace directive can be used for theCppAnnotations::Virtual namespace, and ausing declaration can be used for theCppAnnotations::value variable:using namespace CppAnnotations::Virtual;using CppAnnotations::value;int main(){ value = 0; pointer = 0;}Following ausing namespace directive all entities of that namespacecan be used without any further prefix. If a singleusing namespacedirective is used to refer to a nested namespace, then all entities of thatnested namespace can be used without any further prefix. However, the entitiesdefined in the more shallow namespace(s) still need the shallow namespace'sname(s). Only after providing specificusing namespace directives orusing declarations namespace qualifications can be omitted.
When fully qualified names are preferred but a long name like
CppAnnotations::Virtual::pointer
is considered too long, anamespace alias may be used:
namespace CV = CppAnnotations::Virtual;
This definesCV as analias for the full name. Thevariablepointer may now be accessed using:
CV::pointer = 0;
A namespace alias can also be used in ausing namespace directive orusing declaration:
namespace CV = CppAnnotations::Virtual; using namespace CV;
Nested namespace definitions
Starting with the C++17 standard, when nesting namespaces a nestednamespace can directly be referred to using scope resolution operators. E.g.,
namespace Outer::Middle::Inner { // entities defined/declared here are defined/declared in the Inner // namespace, which is defined in the Middle namespace, which is // defined in the Outer namespace }To define an entity outside of its namespace its name must befullyqualified by prefixing the member by its namespaces. The definition may beprovided at the global level or at intermediate levels in the case of nestednamespaces. This allows us to define an entity belonging to namespaceA::Bwithin the region of namespaceA.
Assume the typeint INT8[8] is defined in theCppAnnotations::Virtualnamespace. Furthermore assume that it is our intent to define a functionsquares, inside the namespaceCppAnnotations::Virtual returning apointer toCppAnnotations::Virtual::INT8.
Having defined the prerequisites within theCppAnnotations::Virtualnamespace, our function could be defined as follows (cf. chapter9for coverage of the memory allocation operatornew[]):
namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } } }The functionsquares defines an array of oneINT8 vector, andreturns its address after initializing the vector by the squares of the firsteight natural numbers.
Now the functionsquares can be defined outside of theCppAnnotations::Virtual namespace:
namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares(); } } CppAnnotations::Virtual::INT8 *CppAnnotations::Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; }In the above code fragment note the following:
squares is declared inside of theCppAnnotations::Virtualnamespace. The definition outside of the namespace region requires us to usethe fully qualified name of the functionand of its return type.Inside the body of the functionsquares we are within theCppAnnotations::Virtual namespace, so inside the function fullyqualified names (e.g., forINT8) are not required any more.Finally, note that the function could also have been defined in theCppAnnotations region. In that case theVirtual namespace would havebeen required when definingsquares() and when specifying its return type,while the internals of the function would remain the same:
namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares(); } Virtual::INT8 *Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } }Sleep andselect can be used for waiting, but as they were designed inan era when multi threading was unavailable, their usefulness islimited when used in multi threaded programs. Multi threading has become partofC++ (covered in detail in chapter20), and additionaltime-related functions are available in thestd::filesystem namespace,covered below in this chapter.
In multi threaded programs threads are frequently suspended, albeit usuallyfor a very short time. E.g., when a thread wants to access a variable, but thevariable is currently being updated by another thread, then the former threadshould wait until the latter thread has completed the update. Updating avariable usually doesn't take much time, but if it takes an unexpectedly longtime, then the former thread may want to be informed about that, so it can dosomething else while the latter thread is busy updating thevariable. Interactions between threads like these cannot be realized withfunctions likesleep andselect.
Thestd::chrono namespace bridges the gap between thetraditionally available time-related functions and the time-relatedrequirements of multi-threading and of thestd::filesystem namespace. All but the specificstd::filesystem related time functionality isavailable after including the<chrono> header file. After including the<filesystem> header file the facilities of thestd::filesystem areavailable.
Time can be measured in various resolutions: in Olympic Games time differencesof hundreds of seconds may make the distinction between gold and silvermedals, but when planning a vacation we might talk about it months before wego on vacation. Time resolutions are specified by objects of the classstd::ratio, which (apart from including the<chrono> header file) isalso available after including the<ratio> header file.
Different events usually last for different amounts of time (given a specifictime resolution). Amounts of time are specified by objects of the classstd::chrono::duration.
Events can also be characterized by their points in time: midnight, January 1,1970 GMT is a point in time, as is 19:00, December 5, 2010. Points in time arespecified by objects of the classstd::chrono::time_point.
It's not just that resolutions, durations of events, and points in time ofevents may differ, but the devices (clocks) we use for specifying time alsodiffer. In the pasthour glasses were used (and sometimes they're stillused when boiling eggs), but on the other hand we may use atomic clocks whenmeasurements should be very precise. Four different types of clocks areavailable. The commonly used clock isstd::chrono::system_clock, but inthe context of the file system there's also astd::chrono::file_clock.
In the upcoming sections the details of thestd::chrono namespace arecovered. First we look at characteristics of time resolutions. How tohandle amounts of time given their resolutions is covered next. The nextsection describes facilities for defining and handling time-points. Therelationships between these types and the various clock-types are coveredthereafter.
In this chapter the specificationstd::chrono:: is often omitted (inpracticeusing namespace std followed byusing namespace chrono iscommonly used;[std::]chrono:: specifications are occasionally used toavoid ambiguities). Also, every now and then you'll encounterforwardreferences to later chapters, like the reference to the chapter aboutmulti-threading. These are hard to avoid, but studying those chaptersat this point can safely be postponed without loss of continuity.
std::ratio.Before the classratio can be used, the<ratio> header file must beincluded. But the frquently included<chrono> header file already includestheratio header file.
The classratio has twotemplate arguments. These are positiveintegral numbers surrounded by pointed brackets defining, respectively, thenumerator and denominator of a fraction (by default the denominator equals1). Examples:
ratio<1> - representing one; ratio<60> - representing 60 ratio<1, 1000> - representing 1/1000.
The classratio defines two directly accessible static datamembers:num represents its numerator,denits denominator. Aratio definition by itself simply defines a certainamount. E.g., when executing the following program
#include <ratio> #include <iostream> using namespace std; int main() { cout << ratio<5, 1000>::num << ',' << ratio<5, 1000>::den << '\n'; }1,200 is displayed, as that's the `amount' represented byratio<5, 1000>:ratio simplifies its fraction whenever possible.
Several predefinedratio types exist. They are, likeratio itself, defined in the standard namespace and can be used instead ofthe more cumbersomeratio<x> orratio<x, y> specifications:
yocto | 10-24 | zepto | 10-21 | ||||
atto | 10-18 | femto | 10-15 | pico | 10-12 | ||
nano | 10-9 | micro | 10-6 | milli | 10-3 | ||
centi | 10-2 | deci | 10-1 | ||||
deca | 101 | hecto | 102 | kilo | 103 | ||
mega | 106 | giga | 109 | tera | 1012 | ||
peta | 1015 | exa | 1018 | ||||
zetta | 1021 | yotta | 1024 | ||||
yocto, zepto, zetta andyottause integral constants exceeding 64 bits. Although these constants are definedinC++, they are not available on 64 bit or smaller architectures.)Time related ratios can very well be interpreted as fractions or multiple ofseconds, withratio<1, 1> representing a resolution of one second.
Here is an example showing how these abbreviations can be used:
cout << milli::num << ',' << milli::den << '\n' << kilo::num << ',' << kilo::den << '\n';
std::chrono::duration.Before using the classduration the<chrono> header file must beincluded.
The classduration has two template arguments. A numeric type (int64_tis normally used) defining the type holding the duration's amount of time, anda time-resolutionratio (called itsresolution).
Often the following predefinedduration types are used:
predefined: | duration type | |
nanoseconds | duration<int64_t, nano> | |
microseconds | duration<int64_t, micro> | |
milliseconds | duration<int64_t, milli> | |
seconds | duration<int64_t> | |
minutes | duration<int64_t, ratio<60>> | |
hours | duration<int64_t, ratio<3600>> | |
E.g., to define a duration of 30 minutes useminutes halfHour{ 30 }.
The suffixesh, min, s, ms, us, ns are available for integral values,creating the correspondingduration times. E.g.,minutes min =1h stores 60 minutes inmin.
Sub-types:
rep: the duration's numeric type (commonlyint64_t);period: theratio type (likekilo). E.g.,minutes::period::num equals 60.Constructors:
duration():duration(Type const &value):value time units (Type refers to the duration's numeric type. E.g., when definingminutes halfHour{ 30 } the argument 30 is stored inside itsint64_t data member).Operators:
Duration types support assignment, negation (e.g.,halfHour =-halfHour), addition and subtraction of duration values, and alsomultiplication, division and modulo computations by numeric factors. Compoundassignment operators are also available. E.g.,
minutes time = 2 * halfHour; // time: 60 minutes time += minutes{ 30 }; // time: 90 minutesMembers:
Type count() const returns the value stored inside theduration object. E.g.,minutes{ 30 }.count() returns 30. The following members are static members;duration::zero() returns an (immutable) duration object whosecount member returns 0. E.g.,seconds::zero().count() returns0s;duration::min() returns an (immutable) duration object whosecount member returns the lowest value of itsrep type (i.e.,std::numeric_limits<duration::rep>::min() (cf. section21.11));duration::max() returns an (immutable) duration object whosecount member returns the maximum value of itsrep type.Conversions:
The precision of left-hand side arguments of assignment operators must begreater than or equal to the precision of the right-hand side arguments(the left-hand argument may not lose precision). When using binaryarithmetic operators the resulting duration type has a precision equal to thefiner of the two precisions. E.g.,
cout << (1min + 1h).count() << '\n'; // shows: 61 hours hr{ 1 }; halfHour += hr; // OK // hr += halfHours; // won't compileDurations can be converted by thestd::chrono::duration_cast<destination>(source) function template, wheredestination is the destination'sduration type andsource is anavailabledestination object, butduration_cast truncates thedestination value whendestination's precision is less thansource'sprecision. E.g.,duration_cast<minutes>(seconds{ 90 }) returnsminutes{ 1 }.
When the left-hand side argument's precisionis less than the right-handside's precision some decision must be made about how to handle the loss ofprecision. The following function template can be used to convert a durationto a less precise type, returning adouble value, which can be, e.g.,truncated or rounded.
template <typename To, typename From> double durationCast(From from) { return static_cast<double>(from.count()) * To::period::den * From::period::num / (To::period::num * From::period::den); }returning adouble value (1.5 when called asdurationCast<minutes>(seconds{ 90 })), leaving the decision how to use thereturneddouble value to the caller.
std::chrono namespace.Before using thechrono clocks the<chrono> header file must beincluded.
`Clock' clock-types are used to define points in time and define thefollowing sub-types:
Clock::duration: the clock's time granularity type (by default usingnanoseconds. E.g.,system_clock::duration oneDay{ 24h };Clock::period: the clock'sstd::ratio type. E.g.,system_clock::period::den;Clock::rep: the type storing amounts of time. By default usingint64_t). E.g.,system_clock::rep amount;Clock::time_point: the type storing time points (covered in the next section). By default usingtime_point<system_clock, nanoseconds> E.g.,system_clock::time_point start.All clocks have a membernow returning the clock type'stime_point corresponding to the current time (relative to the clock'sepoch). It is a static member which can be used like this:system_clock::time_point tp = system_clock::now().
Four clock types are defined in the chrono namespace:
system_clock is the `wall clock', using the system's real time clock;steady_clock is a clock whose time increases in parallel with the increase of real time;high_resolution_clock is the computer's fastest clock (i.e., the clock having the shortest timer-tick interval). In practice this is the same clock assystem_clock.file_clock: used for time specifications of file-system elements.File_clock time specifications use a different starting (epoch) time than the other clocks, but it's easy to convertfile_clock times to/from other clock types.In addition to the membernow the classessystem_clock andhigh_resolution_clock (referred to asClock below) provide two staticmembers:
std::time_t Clock::to_time_t(Clock::time_point const &tp)std::time_t value (the same type as returned byC'stime(2) function) converting atime_point value to atime_t value;Clock::time_point Clock::from_time_t(std::time_tvseconds)time_point corresponding to atime_t value.For example:
system_clock::time_point now = system_clock::now(); time_t value = system_clock::to_time_t(now); system_clock::time_point now2 = system_clock::from_time_t(value); // now2 != now since time_t uses seconds, not nanoseconds
std::chrono::time_point.Before using the classtime_point the<chrono> header file must beincluded.
Likeduration the classtime_point requires two template arguments: Aclock type and a duration type. The standard clock types define their owntime_point types usingnanoseconds as their duration type (time_point by default usesnanoseconds). Thefollowing time point type definitions are therefore identical:
time_point<standard_clock, nanoseconds> time_point<standard_clock> standard_clock::time_point
Constructors:
time_point():system_clock it is January, 1, 1970, 00:00h, but note thatfile_clock::time_point has a different starting point (see the example at the end of this section);Operators:
time_point &operator+=(duration const &amount) adds the amount of time represented byamount to the currenttime_point object;time_point &operator-=(duration const &amount) subtracts the amount of time represented byamount from the currenttime_point object;Type operator<<(std::ostream &, time_point const &) inserts a textual representation of thetime_point's UTC time into theostream.The compound operators are also available as binary arithmetic operators usingatime_point const & and aduration const & operand (in anyorder). Example:
system_clock::now() + seconds{ 5 };Members:
duration time_since_epoch() const:duration is the duration type used by the time point object for which this member is called. To convert the returnedduration to asize_t value usetime_since_epoch().count();time_point min() const: a static member returning the time point'sduration::min value. Example:cout << time_point<system_clock>::min().time_since_epoch().count() << '\n'; // shows -9223372036854775808
time_point max() const: a static member returning the time point'sduration::max value.Conversions:
All predefined clocks use nanoseconds for their duration types. Converting todifferentduration types is covered in the previous section(4.2.2). Alternatively, the membersto_time_t of thesystem_clock and thehigh_resolution_clock can be used to converttheirtime_point values totime_t. Suchtime_t values are commonlyused to convert time to text, e.g., using themanipulatorput_time(cf. section6.3.2). Theput_time manipulator must be providedwith the address of astd::tm object, which can be obtained from astd::time_t value. See figure3 for a visual representation ofthe involved elements.

Use the following blueprint to insert asystem_clock::time pointvalue into astd::ostream (cf. section6.4.4):
int main() { auto now = system_clock::now(); // get a time_point cout << now << '\n'; // now's UTC time // convert to a time_t time_t timeT = system_clock::to_time_t(now); tm *local = localtime(&timeT); // get a tm * cout << put_time(local, "%c") << '\n'; // show the time }To convert atime_point to anotherstd::chrono clock'stime_pointthe templateDestClock::time_point std::chrono::clock_cast<DestClock>(TimePoint tp) can be used. The argumenttp is an availabletime_point, andDestClock specifies the clock type of the returnedtime_point. E.g.,the followingcout statement displays four identical times:
auto fNow = file_clock::now(); auto sNow = file_clock::to_sys(fnow); cout << fNow << '\n' << sNow << '\n' << clock_cast<system_clock>(fNow) << '\n' << clock_cast<file_clock>(sNow) << '\n';
So, where is the starting point of thefile_clock clock?
Sincetime_point's default cconstructor is initialized to its clock'sstarting point it can be obtained this way:
cout << file_clock::time_point{}<< '\n'; // shows: 2174-01-01 00:00:00.000000000truncate(2),opendir(2), andrealpath(3)) are of course also available inC++, but their signaturesand way of use are often less attractive as they usually expectchar const* parameters and may use static buffers or memory allocation based onmalloc(3) andfree(3).Since 2003 theBoost library offerswrappers around these functions,offering interfaces to those system calls that are moreC++-like.
CurrentlyC++ directly supports these functions in thestd::filesystem namespace. These facilities can be usedafter including the<filesystem> header file.
Thefilesystem namespace is extensive: it contains more than 10 differentclasses, and more than 30 free functions. To refer to the identifiers definedin thestd::filesystem namespace their fully qualified names (e.g.,std::filesystem::path) can be used. Alternatively, after specifying`using namespace std::filesystem;' the identifiers can be used withoutfurther qualifications. Namespace specifications like `namespace fs =std::filesystem;' are also encountered, allowing specifications likefs::path.
Functions in thefilesystem namespace may fail. When functions cannotperform their assigned tasks they may throw exceptions (cf. chapter10) or they may assign values toerror_code objects thatare passed as arguments to those functions (see section4.3.1 below).
std::error_code (note:notstd::filesystem::error_code!) encapsulateerror values, andassociatederror categories (cf. section10.9;error_codecan be used after including the<system_error> header, but it is alsoavailable after including the<filesystem> header file). Traditionallyerror values are available as values assigned to the globalinterrno variable. By convention, whenerrno's value equals zero there's noerror. This convention was adopted byerror_code.Error codes can be defined for many conceptually different situations. Thosesituations are characterized by their ownerror categories.
Error categories are used to associateerror_code objects with the errorsthat are defined by those categories. Default available error categories mayuse values likeEADDRINUSE (or the equivalentenum class errc valueaddress_in_use) but new types of error categories, tailored to othercontexts, can also be defined. Theenum class errc is defined in the<bits/error_constants.h> header file. Error categories and how to definethem is covered near the end of theC++ Annotations (section23.7.1).
Constructors:
error_code() noexcept:system_category error category. Value 0 is not considered an error;error_code(int ec, error_category const &cat) noexcept:ec (e.g.,errno, set by a failing function), and a const reference to the applicable errorcategory (provided by, e.g.,std::system_category() orstd::generic_category()). Here is an example defining anerror_code object: error_code ec{ 5, system_category() };error_code(ErrorCodeEnum value) noexcept:template <class ErrorCodeEnum>. It initializes the object with the return value ofmake_error_code(value) (see below). In section23.7 definingErrorCodeEnums is covered. Note:ErrorCodeEnum as such does not exist. It is a mere placeholder for existingErrorCodeEnum enumerations;Operators:
ErrorCodeEnum are available;operator std::errc() const noexcept:errc error-code value. Forg++ these are defined in theenum class errc in the file/usr/include/x86_64-linux-gnu/c++/14/bits/error_constants.h;explicit operator bool() const noexcept:true if the object's error value is unequal 0 (i.e., it represents and error).Members:
void assign(int val, error_category const &cat):ec.assign(0, generic_category());error_category const &category() const noexcept:void clear() noexcept:error_code's value to 0 and its error category tosystem_category;error_condition default_error_condition() const noexcept:error_condition);string message() const:category().message(ec.value()));int value() const noexcept:Free functions:
error_code objects can be compared for (in) equality and can be ordered (usingoperator<).Orderingerror_codes associated with different error categories has no meaning. But when the error categories are identical then they are compared by their error code values (cf. thisSG14 discussion summary);
error_code make_error_code(errc value) noexcept:error_code object initialized withstatic_cast<int>(value) andgeneric_category(). This function converts anenum class errc value to anerror_code.Other error related enums may also be defined with which tailoredmake_error_code functions can be associated (cf. section23.7;)
std::ostream &operator<<(std::ostream & os, error_code const &ec):return os << ec.category().name() << ':' << ec.value();
Manyfilesystem functions define an optional lasterror_code &ecparameter. Those functions havenoexcept specifications. If thosefunctions cannot complete their tasks, thenec is set to the appropriateerror code, callingec.clear() if no error was encountered. If noecargument is provided then those functions throw afilesystem_errorexception if they cannot complete their tasks.
path objects, cf. section4.3.3below), have attributes: permissions (e.g., the owner may modify an entry),and types (like files, directories, and soft-links). Those attributes aredefined in the classstd::filesystem::file_status.Types:
Defined in the(std::filesystem) enum class file_type.
| std::filesystem::file_type | |
Type | Meaning |
not_found (= -1) | the file system entry was not found (not considered an error) |
none | the file status has not yet been evaluated or an error occurred when evaluating the status |
regular | a regular file |
directory | a directory |
symlink | a symbolic link |
block | a block device |
character | a character device |
fifo | a named pipe |
socket | a socket file |
unknown | an unknown file type |
Permissions:
Defined in the(std::filesystem) enum class perms.
The enumeration's symbols were defined to make their meanings more descriptivethan the constants defined in the<sys/stat.h> header file, but theirvalues are identical. Theenum class perms supports all bitwise operators.
| std::filesystem::perms | |||
| Symbol | Value | sys/stat.h | Meaning |
none | 0000 | --- | No permission bits were set |
owner_read | 0400 | S_IRUSR | File owner has read permission |
owner_write | 0200 | S_IWUSR | File owner has write permission |
owner_exec | 0100 | S_IXUSR | File owner has execute/search permissions |
owner_all | 0700 | S_IRWXU | File owner has read, write, and execute/search permissions |
group_read | 0040 | S_IRGRP | The file's group has read permission |
group_write | 0020 | S_IWGRP | The file's group has write permission |
group_exec | 0010 | S_IXGRP | The file's group has execute/search permissions |
group_all | 0070 | S_IRWXG | The file's group has read, write, and execute/search permissions |
others_read | 0004 | S_IROTH | Other users have read permission |
others_write | 0002 | S_IWOTH | Other users have write permission |
others_exec | 0001 | S_IXOTH | Other users have execute/search permissions |
others_all | 0007 | S_IRWXO | Other users have read, write, and execute/search permissions |
all | 0777 | --- | All users have read, write, and execute/search permissions |
set_uid | 04000 | S_ISUID | Set user ID to file owner user ID on execution |
set_gid | 02000 | S_ISGID | Set group ID to file's user group ID on execution |
sticky_bit | 01000 | S_ISVTX | POSIX XSI specifies that when set on a directory only file owners may delete files even if the directory is writeable by others (used, e.g., with /tmp) |
mask | 07777 | --- | All valid permission bits. |
Perm_options:
The(std::file_system) enum class perm_options specifies the way filesystem entries are modified
| std::filesystem::perm_options | |
Value | Meaning |
replace | current permisions are replaced new permissions |
remove | the specified permissions are removed from the file system entry's current permissions |
nofollow | when the current file system entry refers to a symbolic link the permissions of the symbolic link itself are updated |
Constructors:
explicit file_status(file_type type = file_type::none, perms permissions = perms::unknown)Members:
perms permissions() const returns the permissions of the file system entry represented by thefile_status object.permissions changing the permissions of a file system entry;file_type type() const returns the type of the file system entry to which thefile_status object refers;void type(file_type type) changes the type of the file system entry to which thefile_tatus object refers.std::path free functionsstatus andsymlink_status(cf. section4.3.3.2) return thefile_status of file system entries.The following functions provide specific information about the status offile system entries:
bool status_known(file_status const &status) returnstrue ifstatus refers to a determined status (status itself may indicate that the entity referred to bystatus does not exist). One way of receivingfalse is by passing it a default status object:status_known(file_status{});bool is_WHATEVER(file_status status), replacingWHATEVER by the requested file type, returnstrue ifstatus refers to an entry of the specified type.These followingis_WHATEVER functions are available:
| is_WHATEVER(file_status) | |
Function | Meaning |
is_block_file | 'entry' is a block device |
is_character_file | 'entry' is a character device |
is_directory | 'entry' is a directory |
is_empty | 'entry' is an empty file or directory |
is_fifo | 'entry' is a named pipe |
is_other | 'entry' is not a directory, regular file or symlink |
is_regular_file | 'entry' is a regular file |
is_socket | 'entry' is a named socket |
is_symlink | 'entry' is a symbolic link |
Here is a small program showing how file statuses can be obtained anddisplayed (cf. sections4.3.3 and (for themap) section12.3.7):
namespace { std::unordered_map<file_type, char const *> statusMap = { { file_type::not_found, "an unknown file" }, { file_type::none, "not yet or erroneously evaluated " "file type" }, { file_type::regular, "a regular file" }, { file_type::directory, "a directory" }, { file_type::symlink, "a symbolic link" }, { file_type::block, "a block device" }, { file_type::character, "a character device" }, { file_type::fifo, "a named pipe" }, { file_type::socket, "a socket file" }, { file_type::unknown, "an unknown file type" } }; } int main() { cout << oct; string line; while (true) { cout << "enter the name of a file system entry: "; if (not getline(cin, line) or line.empty()) break; path entry{ line }; error_code ec; file_status stat = status(entry, ec); if (not status_known(stat)) { cout << "status of " << entry << " is unknown. " "Ec = " << ec << '\n'; continue; } cout << "status of " << entry << ": type = " << statusMap[stat.type()] << ", permissions: " << static_cast<size_t>(stat.permissions()) << '\n'; } }filesysten::path commonly contain names offile system entries.Constructors:
path(): the default constructor is initialized with an emptypath;path(InputIter begin, InputIter end):begin toend define thepath's name.std::string andchar const *.path object doesn't have to refer to an existing file systementry.path constructors may contain (all optional):E:) or device indicator (like//nfs);.) indicates the current directory and the `double dot filename' (..) indicates the current directory's parent directory;The constructors also define a lastformat ftmp = auto_formatparameter, for which in practice almost never an argument has to be provided(for its details seecppreference.)
path &operator/=(Type const &arg):arg argument is separated from the path's current content by a directory separator (unless the path is initially empty as incout << path{}.append("entry")). See also the membersappend andconcat, below. The free operator/ accepts twopath (promotable) arguments, returning apath containing both paths separated by a directory separator (e.g.,lhs / rhs returns thepath objectlhs/rhs);path &operator+=(Type const &arg):/=, butno directory separator is used when addingarg to the currentpath;path objects can be compared using the (operators implied by the)== and<=> operators. Path objects are compared by lexicographical comparing their ascii-character content;ostream &operator<<(ostream &out, path const &path) (stream insertion) insertspath's content, surrounded by double quotes, intoout;istream &operator>>(istream &in, path &path) extractspath's content fromin. The extracted path name may optionally be surrounded by double quotes. When inserting a previously extractedpath object only one set of surrounding quotes are shown.Accessors:
Accessors return specificpath components. If a path doesn't contain the requested component then an emptypath is returned.
char const *c_str(): the path's content is returned as an NTBS;path extension() returns the dot-extension of the path's last component (including the dot);path filename() returns the last path-content of the currentpath object. See also thestem() accessor, below;bool is_absolute(): returnstrue if thepath object contains an absolute path specification;bool is_relative(): returnstrue if thepath object contains a relative path specification;path parent_path() returns the current path-content from which the last element has been removed. Note that if thepath object contains a filename's path (like"/usr/bin/zip") thenparent_path removes/zip and returns/usr/bin, so notzip's parent directory, but its actual directory;path relative_path(): returns the path's content beyond the path's root-directory component of thepath object. E.g., if thepath ulb{ "/usr/local/bin" } is defined thenulb.relative_path() returns a path containing"usr/local/bin";path root_directory(): returns the root-directory component of thepath object;path root_name(): returns the root-name's component of thepath object;path root_path(): returns the root-path component of thepath object;path stem() returns the last path-content of the currentpath object from which the dot-extension hash been removed;string(): returns the path's content as astd::string.wstring, u8string, u16string, , u32string, generic_string, generic_wstring, generic_u8string, generic_u16string, andgeneric_u32string;Except for the family ofstring() and theis_... accessors, there are alsobool has_... members returningtrue if thepath contains the specified component (e.g.,has_extension returnstrue if thepath contains an extension).
Member functions:
path &append(Type const &arg) acts like the/= operator;path::iterator begin() returns an iterator containing the first path component; Dereferencing apath::iterator returns apath object.path::iterators the individual directories and finally filename components are returned. The directory separators themselves are not returned when dereferencing subsequentpath::iterators;path::const_iterator begin() const returns a iterator to the immutable first path component; Dereferencing apath::const_iterator returns apath const object;void clear(): thepath's content is erased;int compare(Type const &other):other.Other can be apath, a string-type or an NTBS;path &concat(Type const &arg) acts like the+= operator;path::iterator end() returns an iterator beyond the last path component;path::const_iterator end() const returns an iterator beyond the immutable last path componentpath &remove_filename():/. If thepath doesn't contain a slash then thepath object's cleared;path &replace_extension(path const &replacement = path{} ):replacement. The extension is removed ifreplacement is empty. If thepath callingreplace_extension has no extension thenreplacement is added. The replacement may optionally start with a dot. The path object's extension receives only one dot;path &replace_filename(path const &replacement):replacement, which itself may contain multiple path elements. If only a root-directory is stored, then it is replaced byreplacement. The member's behavior is undefined if the current path object is empty;Defined in the(std::filesystem) enum class copy_options.
The enumeration supports bitwise operators.Thecopy_options enum values are used to fine-tune the behavior offilesystem functions copying file system elements.
| std::filesystem::copy_options | |||
Symbol | Value | Meaning | |
none | 0 | default: copy like cp | |
overwrite_existing | 2 | replace the destination file | |
update_existing | 4 | replace the destination file only if it is older than the file being copied | |
recursive | 8 | recursively copy subdirectories and their content | |
copy_symlinks | 16 | copy symlinks as symlinks | |
skip_symlinks | 32 | ignore symlinks | |
directories_only | 64 | copy the directory structure, but do not copy any non-directory files | |
create_symlinks | 128 | create symlinks instead of copying files. The source path must be an absolute path unless the destination path is in the current directory | |
create_hard_links | 256 | instead of copying files create hard links resolving to the same files as the original | |
Functions:
path absolute(path const &src, [, error_code &ec]):src as an absolute path (i.e., starting at the filesystem's root (and maybe disk) name). It can be called as, e.g.,absolute("tmp/filename"), returning the (absolute) current working directory to whichabsolute's argument is appended as a final element, separated by a directory separator. Relative path indicators (like../ and./) are kept;path canonical(path const &src [, error_code &ec]):src's canonical path.Src must exist. Example: canonical("/usr/local/bin/../../share/man"); // returns path{ "/usr/share/man" }void copy(path const &src, path const &dest [, copy_options opts [, error_code &ec]]):src must exist. By default copiessrc todest if thecp program would also succeed. Useopts to fine-tunecopy's behavior.src is a directory, anddest does not exist,dest is created. Directories are recursively copied if copy optionsrecursive ornone were specified;bool copy_file(path const &src, path const &dest [, copy_options opts [, error_code &ec]]):src must exist. Copiessrc todest if thecp program would also succeed. Symbolic links are followed. The valuetrue is returned if copying succeeded;void copy_symlink(path const &src, path const &dest [, error_code &ec]):dest as a copy of the symlinksrc;bool create_directories(path const &dest [, error_code &ec]):dest, unless already existing. E.g., using argument"a/b/c" and"a" doesn't yet exist then"a/b/c" are all created. The valuetrue is returned ifdest was actually created. Iffalse is returnedec contains an error-code, which is zero (ec.value() == 0) ifdest already existed. See alsocreate_directory below;bool create_directory(path const &dest [, path const &existing] [, error_code &ec]):dest's parent directory must exist. This function creates directorydest if it does not yet exist. Nested subdirectories are not created bycreate_directory: using argument"a/b/c" and neither"a" nor"a/b" exist then this function fails. The valuetrue is returned ifdest was actually created. Iffalse is returnedec contains an error-code, which is zero (ec.value() == 0) ifdest already existed. Ifexisting is specified, thendest receives the same attributes asexisting;void create_directory_symlink(path const &dir, path const &link [, error_code &ec]):create_symlink (see below), but is used to create a symbolic link to a directory;void create_hard_link(path const &dest, path const &link [, error_code &ec]):link todest.Dest must exist;void create_symlink(path const &dest, path const &link [, error_code &ec]):link todest;dest doesnot have to exist;path current_path([error_code &ec]),void current_path(path const &toPath [, error_code &ec]):toPath. The returned path's last character is not a slash, unless called from the root-directory;bool equivalent(path const &path1, path const &path2 [, error_code &ec]):true is returned ifpath1 andpath2 refer to the same file or directory, and have identical statuses. Both paths must exist;bool exists(path const &dest [, error_code &ec]),exists(file_status status):true is returned ifdest exists (actually: ifstatus(dest[, ec]) (see below) returnstrue). Note: when iterating over directories, the iterator usually provides the entries' statuses. In those cases callingexists(iterator->status()) is more efficient than callingexists(*iterator). Whendest is the path to a symbolic reference thenexists returns whether the link's destination exists or not (see also the functionsstatus andsymlink_status in section4.3.4);std::unintmax_t file_size(path const &dest [, error_code &ec]):std::uintmax_t hard_link_count(path const &dest [, error_code &ec]):dest;file_clock::time_point last_write_time(path const &dest [, error_code &ec]),void last_write_time(path const &dest, file_clock::time_point newTime [, error_code &ec]):dest's last modification time; the latter function changesdest's last modification time tonewTime.last_write_time's return type is defined through ausing alias forchrono::time_point (cf. section4.2.4). The returnedtime_point is guaranteed to cover all file time values that may be encountered in the current file system. The functionfile_clock::to_sys (see below) can be used to convertfile_clock time points tosystem_clock time_points;void permissions(Path const &entry, perms newPerms [, perm_options opts = perm_options::replace ] [, error_code &ec]):entry. Each of the two last arguments is optional. E.g., when specifying anerror_code as third argument thenopts is implicitly specified asreplace;path read_symlink(path const &src [, error_code &ec]):src must refer to a symbolic link or an error is generated. The link's target is returned;bool remove(path const &dest [, error_code &ec]),std::uintmax_t remove_all(path const &dest [, error_code &ec]):remove removes the file, symlink, or empty directorydest, returningtrue ifdest could be removed;remove_all removesdest if it's a file (or symlink); and recursively removes directorydest, returning the number of removed entries;void rename(path const &src, path const &dest [, error_code &ec]):src todest, as if using the standardmv(1) command (ifdest exists it is overwritten);void resize_file(path const &src, std::uintmax_t size [, error_code &ec]):src's size is changed tosize as if using the standardtruncate(1) command;space_info space(path const &src [, error_code &ec]):src is located;file_status status(path const &entry [, error_code &ec]):entry's file_status. Ifentry is the name of a symbolic link then the status of the link's destination is returned;file_status symlink_status(path const &entry [, error_code &ec]):entry's ownfile_status;path system_complete(path const &src[, error_code& ec]):src, usingcurrent_path as its base;path temp_directory_path([error_code& ec]):TMPDIR,TMP, TEMP, orTEMPDIR. Otherwise,/tmp is returned.system_clock::time_point file_clock::to_sys(file_clock::time_point timePoint):last_write_time can be represented using thesystem_clock's epoch:int main(){ time_t seconds = system_clock::to_time_t( file_clock::to_sys(last_write_time("lastwritetime.cc")) ); cout << "lastwritetime.cc's last (UTC) write time: " << put_time(gmtime(&seconds), "%c") << '\n';}In thestd::filesystem namespace the elements of directories are objectsof the classdirectory_entry, containing names and statuses of the entriesof that directory.
Constructors:
The classdirectory_entry supports all standard constructors (andassignment operators) and also a constructor expecting apath:
directory_entry(path const &entry);
Objects of the classdirectory_entry can be constructed by name, and donot have to refer to existing entries in the file system.
Operators:
ostream &operator<<(ostream &, directory_entry const &) inserts the object'spath into theostream;==, <=>) compare theirstd::path data members;path const &path() const,operator path const &() const returns the current object's path name.Members:
void assign(path const &dest):dest (identical todirectory_entry's assignment operator);void replace_filename(path const &dest):dest. If that element is empty (e.g., when the object's path ends in a directory separator) thendest is appended to the current object's path;filesystem::file_status status([error_code &ec]):symlink_status (see also section4.3.2 and4.3.2.1 below).filesystem namespace has two classes simplifying directoryprocessing: objects of the classdirectory_iterator are (input) iteratorsiterating over the entries of directories; and objects of the classrecursive_directory_iterator are (input) iterators recursively visitingall entries of directories.locationenum class directory_options
Theenum class directory_options defines values thatare used to fine-tune the behavior ofrecursive_directory_iteratorobjects, supporting bitwise operators (the values of its symbols are shownbetween parentheses):
none (0): directory symlinks are skipped, denied permission to enter a sub-directory generates an error;follow_directory_symlink (1): symlinks to sub-directories are followed;skip_permission_denied (2): directories that cannot be entered are silently skipped.Constructors:
(recursive_)directory_iterator():(recursive_)directory_iterator's iterator-range;(recursive_)directory_iterator(path const &from [, error_code &ec]):(recursive-)directory_iterator usingfrom as the starting directory of the iterator. All members of standard input iterators (cf. section18.2) are supported;recursive_directory_iterator(path const &from, directory_options opts [, error_code &ec]):(recursive-)directory_iterator fine-tuning its behavior to the options specified byopts.Copy, and move constructors are available.
These iterators point todirectory_entry objects referring to entries in the computer's file system. E.g.,
cout << *directory_iterator{ "/home" } << '\n'; // shows the first entry under /home(Recursive_)directory_iterators can be used with range-based for-loopsand in standardfor andwhile statements.
Additional members of recursive_directory_iterators
int depth() const:void disable_recursion_pending():depth() returns that specific depth this member must be called each time before the iterator's increment operator is called;recursive_directory_iterator &increment(error_code &ec):operator++ throws afilesystem_error exception, whileincrement assigns the error toec;directory_options options() const:void pop():bool recursion_pending() const:true is returned if recursive processing of sub-directories of the currently processed directory is allowed. If so, and the the iterator points at a sub-directory, then processing continues in that sub-directory at the iterator's next increment;Here's a small program displaying all elements andall immediate sub-directories of a directory:
int main() { recursive_directory_iterator base{ "/var/log", directory_options::skip_permission_denied }; for (auto entry = base, endIt = end(base); entry != endIt; ++entry) { cout << entry.depth() << ": " << *entry << '\n'; if (entry.depth() == 1) entry.disable_recursion_pending(); } }The above program handles entries as they come. Other strategies must beimplemented `by hand'. E.g., a breadth-first strategy first visits all thenon-directory entries and then visits the sub-directories, as illustrated inthe next example by processingthe directories stored inlevel in turn(initially it merely contains the starting directory).
`Processing a directory' means that its non-directory entries are directlyprocessed storing the names of sub-directories innext. Onceall entries atlevel have been processed the names of the next levelsub-directories are available (innext). By assigningnext tolevel all directories at the next level are processed. When reaching themost deeply nested sub-directories itsnext is empty and thewhilestatement ends:
void breadth(path const &dir) // starting dir. { vector<path> level{ dir }; // currently processed level while (not level.empty()) // process all its dirs. { vector<path> next; // dirs of the next level for (auto const &dir: level) // visit all dirs at this level { cout << "At " << dir << '\n'; // at each dir: visit all entries for (auto const &entry: directory_iterator{ dir }) { if (entry.is_directory()) // store all dirs at the current next.push_back(entry); // level else // or process its non-dir entry cout << " entry: " << entry << '\n'; } } level = next; // continue at the next level, } // which eventually won't exist }path lives in a file system, Sizes of file systemstypically are quite large, but there is a limit to their sizes.The size of file systems, the number of bytes that is currently being usedand the remaining number of bytes is made available by the functionspace(path const &entry [,error_code &ec]), returning the information about the file system containingentry in a PODstruct space_info.
If theerror_code argument is provided then it is cleared if no erroroccurs, and set to the operating system's error code if an error hasoccurred. If an error occurs and theerror_code argument was not providedthen afilesystem_error exception is thrown, receivingpath as itsfirst argument and the operating system's error code as itserror_codeargument.
The returnedspace_info has three fields:
uintmax_t capacity; // total size in bytes uintmax_t free; // number of free bytes on the file system uintmax_t available; // free bytes for a non-privileged process
If a field cannot be determined it is set to -1 (i.e., the max. value ofthe typeuintmax_t).
The function can be used this way:
int main() { path tmp{ "/tmp" }; auto pod = space(tmp); cout << "The filesystem containing /tmp has a capacity of " << pod.capacity << " bytes,\n" "i.e., " << pod.capacity / (1024 * 1024) << " MB.\n" "# free bytes: " << pod.free << "\n" "# available: " << pod.available << "\n" "free + available: " << pod.free + pod.available << '\n'; }std::filesystem namespace offers its own exception typefilesystem_error (see also chapter10). Its constructor hasthe following signature (the bracketed parameters are optional):filesystem_error(string const &what, [path const &path1, [path const &path2,]] error_code ec);
Asfilesystem facilities are closely related to standard systemfunctions,errc error code enumeration values can be used to obtainerror_codes to pass tofilesystem_error, as illustrated by thefollowing program:
int main() try { try { throw filesystem_error{ "exception encountered", "p1", "p2", make_error_code(errc::address_in_use) }; } catch (filesystem_error const &fse) { cerr << "what: " << fse.what() << "\n" "path1: " << fse.path1() << "\n" "path2: " << fse.path2() << "\n" "code: " << fse.code() << '\n'; throw; } } catch (exception const &ec) { cerr << "\n" "plain exception's what: " << ec.what() << "\n\n"; }