{"id":5440,"date":"2018-05-18T16:19:53","date_gmt":"2018-05-18T16:19:53","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-taking-care-of-your-child-thread\/"},"modified":"2018-05-18T16:19:53","modified_gmt":"2018-05-18T16:19:53","slug":"c-core-guidelines-taking-care-of-your-child-thread","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-taking-care-of-your-child-thread\/","title":{"rendered":"C++ Core Guidelines: Taking Care of your Child Thread"},"content":{"rendered":"<p>When you create a new child thread, you must answer an important question: should you wait for the child or&nbsp;detach yourself from it? If you detach yourself from the newly created child, and your child uses variables that are bound to your life as creator a new question arises: Will the variables stay valid during the lifetime of the child thread?<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;If you don&#8217;t carefully handle your child thread&#8217;s lifetime and variables, you will end with a high probability of undefined behavior.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5439\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/05\/gleise.jpg\" alt=\"gleise\" width=\"700\" height=\"466\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/05\/gleise.jpg 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/05\/gleise-300x200.jpg 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/05\/gleise-1024x682.jpg 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/05\/gleise-768x512.jpg 768w\" sizes=\"auto, (max-width: 700px) 100vw, 700px\" \/><\/p>\n<p>Here are&nbsp;the&nbsp;rules for today that deal exactly with the life issues of the child thread and its variables.<\/p>\n<ul>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-join\">CP.23: Think of a joining <code class=\"highlighter-rouge no-highlight\">thread<\/code> as a scoped container<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-detach\">CP.24: Think of a <code class=\"highlighter-rouge no-highlight\">thread<\/code> as a global container<\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-joining_thread\">CP.25: Prefer <code class=\"highlighter-rouge no-highlight\">gsl::joining_thread<\/code> over <code class=\"highlighter-rouge no-highlight\">std::thread<\/code><\/a><\/li>\n<li><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-detached_thread\">CP.26: Don\u2019t <code class=\"highlighter-rouge no-highlight\">detach()<\/code> a thread<\/a><\/li>\n<\/ul>\n<p>The rules of today depend strongly on each other.<\/p>\n<p>Rule CP.23 and CP.24 about a scoped versus global container may sound a little bit weird, but they are quite good to explain the difference between a child thread which you join or detach.<\/p>\n<h3><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-join\">CP.23: Think of a joining <code class=\"highlighter-rouge no-highlight\">thread<\/code> as a scoped container <\/a>and <a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-detach\">CP.24: Think of a <code class=\"highlighter-rouge no-highlight\">thread<\/code> as a global container<\/a><\/h3>\n<p>Here is a slight variation of the code snippet from the C++ core guidelines:<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">f<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> p)\r\n{\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n    <span style=\"color: #555555;\">*<\/span>p <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">99<\/span>;\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> glob <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">33<\/span>;\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">some_fct<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> p)                <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n{\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> x <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">77<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t0(f, <span style=\"color: #555555;\">&amp;<\/span>x);           <span style=\"color: #0099ff; font-style: italic;\">\/\/ OK<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(f, p);            <span style=\"color: #0099ff; font-style: italic;\">\/\/ OK<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(f, <span style=\"color: #555555;\">&amp;<\/span>glob);        <span style=\"color: #0099ff; font-style: italic;\">\/\/ OK<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> q <span style=\"color: #555555;\">=<\/span> make_unique<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>(<span style=\"color: #ff6600;\">99<\/span>);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t3(f, q.get());      <span style=\"color: #0099ff; font-style: italic;\">\/\/ OK<\/span>\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n    t0.join();\r\n    t1.join();\r\n    t2.join();\r\n    t3.join();\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> <span style=\"color: #cc00ff;\">some_fct2<\/span>(<span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">*<\/span> p)               <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n{\r\n    <span style=\"color: #007788; font-weight: bold;\">int<\/span> x <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">77<\/span>;\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t0(f, <span style=\"color: #555555;\">&amp;<\/span>x);           <span style=\"color: #0099ff; font-style: italic;\">\/\/ bad<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t1(f, p);            <span style=\"color: #0099ff; font-style: italic;\">\/\/ bad<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t2(f, <span style=\"color: #555555;\">&amp;<\/span>glob);        <span style=\"color: #0099ff; font-style: italic;\">\/\/ OK<\/span>\r\n    <span style=\"color: #006699; font-weight: bold;\">auto<\/span> q <span style=\"color: #555555;\">=<\/span> make_unique<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>(<span style=\"color: #ff6600;\">99<\/span>);\r\n    std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t3(f, q.get());      <span style=\"color: #0099ff; font-style: italic;\">\/\/ bad<\/span>\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n    t0.detach();\r\n    t1.detach();\r\n    t2.detach();\r\n    t3.detach();\r\n    <span style=\"color: #0099ff; font-style: italic;\">\/\/ ...<\/span>\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The only difference between the functions <span style=\"font-family: courier new, courier;\">some_fct<\/span> (1) and <span style=\"font-family: courier new, courier;\">some_fct2<\/span> (2) is that the first variations join its created thread but the second variation detaches all created threads.<\/p>\n<p>First of all, you have to join or detach the child thread. If you won&#8217;t do it, you will get a <span style=\"font-family: courier new, courier;\">std::terminate<\/span> exception in the destructor of the child thread. I will write about this issue in the next rule CP.25.<\/p>\n<p>Here is the difference between joining of detaching a child thread:<\/p>\n<ul>\n<li>To<strong> join<\/strong> a thread means according to the guidelines that your thread is a kind of scoped container. What? The reason is that the <span style=\"font-family: courier new, courier;\">thr.join()<\/span> call on a thread <span style=\"font-family: courier new, courier;\">thr<\/span> is a synchronization point. <span style=\"font-family: courier new, courier;\">thr.join()<\/span> guarantees that the creator of the thread will wait until its child is done. To put it the other way around. The child thread <span style=\"font-family: courier new, courier;\">thr<\/span> can use all variables (state) of the enclosing scope in which it was created. Consequently, all calls of the function&nbsp;<span style=\"font-family: 'courier new', courier;\">f<\/span> are well-defined.<\/li>\n<li>On the contrary, this will not hold if you <strong>detach<\/strong> all your child threads. Detaching means, you will lose the handle on your child and your child can even outlive you. Due to this fact, it&#8217;s only safe to use in the child thread variables with global scope. According to the guidelines, your child thread is a kind of global container. Using variables from the enclosing scope is,&nbsp;in this case, undefined behavior.<\/li>\n<\/ul>\n<p>Let me give you an analogy if you are irritated by a detached thread. When you create a file and lose the handle, the file will still exist. The same holds for a detached thread. If you detach a thread, the &#8220;thread of execution&#8221; will continue to run, but you lose the handle to the &#8220;thread of execution&#8221;. You may guess it: <span style=\"font-family: courier new, courier;\">t0<\/span> is just the handle to the thread of execution that was started with the call <span style=\"font-family: courier new, courier;\">std::thread t0(f, &amp;x).<\/span><\/p>\n<p>As I already mentioned you have to join or detach the child thread.<\/p>\n<\/p>\n<h3><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-joining_thread\">CP.25: Prefer <code class=\"highlighter-rouge no-highlight\">gsl::joining_thread<\/code> over <code class=\"highlighter-rouge no-highlight\">std::thread<\/code><\/a><\/h3>\n<p>In the following program, I forgot to join the thread <span style=\"font-family: courier new, courier;\">t<\/span>.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ threadWithoutJoin.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t([]{std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;});\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The execution of the program ends abruptly.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4732\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/04\/threadForgetJoin.png\" alt=\"threadForgetJoin\" width=\"400\" height=\"143\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/04\/threadForgetJoin.png 541w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/04\/threadForgetJoin-300x107.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>And now the explanation:<\/p>\n<p>The lifetime of the created thread <span style=\"font-family: 'courier new', courier;\">t<\/span> ends with its callable unit. The creator has two choices. First: it waits until its child is done (<span style=\"font-family: courier new, courier;\">t.join()<\/span>). Second: it detaches itself from its child: <span style=\"font-family: courier new, courier;\">t.detach()<\/span>. A thread <span style=\"font-family: courier new, courier;\">t <\/span>with a&nbsp;callable unit&nbsp; &#8211; you can create threads without callable units &#8211; is called joinable if neither a t.join() nor t.detach() call happened. The destructor of a joinable thread throws a std<span style=\"font-family: 'courier new', courier;\">::terminate<\/span> exception which ends in&nbsp;<span style=\"font-family: courier new, courier;\">std::abort<\/span>. Therefore, the program terminates.<\/p>\n<article>The rule is called &#8220;Prefer <span style=\"font-family: courier new, courier;\">gsl::joining_thread<\/span> over <span style=\"font-family: courier new, courier;\">std::thread&#8221; <\/span>because a <span style=\"font-family: courier new, courier;\">gsl::joinging_thread<\/span> joins automatically at the end of its scope. Sad to say, but I found no implementation of the gsl<span style=\"font-family: 'courier new', courier;\">::joining_thread<\/span> in the <a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#S-gsl\">guidelines support library<\/a>. Thanks to the <span style=\"font-family: courier new, courier;\">scoped_thread<\/span> from <a href=\"https:\/\/www.justsoftwaresolutions.co.uk\/blog\/\">Anthony Williams<\/a>, this is not a problem:<\/p>\n<article>\n<article>&nbsp; <code class=\"highlighter-rouge no-highlight\"><\/code><code class=\"highlighter-rouge no-highlight\"><\/code><\/article>\n<\/article>\n<\/article>\n<article><\/article>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #0099ff; font-style: italic;\">\/\/ scoped_thread.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;thread&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;utility&gt;<\/span>\r\n\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">class<\/span> <span style=\"color: #00aa88; font-weight: bold;\">scoped_thread<\/span>{\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t;\r\n<span style=\"color: #9999ff;\">public:<\/span>\r\n  <span style=\"color: #006699; font-weight: bold;\">explicit<\/span> <span style=\"color: #cc00ff;\">scoped_thread<\/span>(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t_)<span style=\"color: #555555;\">:<\/span> t(std<span style=\"color: #555555;\">::<\/span>move(t_)){\r\n    <span style=\"color: #006699; font-weight: bold;\">if<\/span> ( <span style=\"color: #555555;\">!<\/span>t.joinable()) <span style=\"color: #006699; font-weight: bold;\">throw<\/span> std<span style=\"color: #555555;\">::<\/span>logic_error(<span style=\"color: #cc3300;\">\"No thread\"<\/span>);\r\n  }\r\n  <span style=\"color: #555555;\">~<\/span>scoped_thread(){\r\n    t.join();\r\n  }\r\n  scoped_thread(scoped_thread<span style=\"color: #555555;\">&amp;<\/span>)<span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\r\n  scoped_thread<span style=\"color: #555555;\">&amp;<\/span> <span style=\"color: #006699; font-weight: bold;\">operator<\/span><span style=\"color: #555555;\">=<\/span>(scoped_thread <span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #555555;\">&amp;<\/span>)<span style=\"color: #555555;\">=<\/span> <span style=\"color: #006699; font-weight: bold;\">delete<\/span>;\r\n};\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> <span style=\"color: #cc00ff;\">main<\/span>(){\r\n\r\n  scoped_thread t(std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span>([]{std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>this_thread<span style=\"color: #555555;\">::<\/span>get_id() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;}));\r\n\r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The <span style=\"font-family: 'courier new', courier;\">scoped_thread<\/span> checks in its constructor if the given thread is joinable and joins in its destructor the given thread.<\/p>\n<h3><a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-detached_thread\">CP.26: Don\u2019t <code class=\"highlighter-rouge no-highlight\">detach()<\/code> a thread<\/a><\/h3>\n<p>This rule sounds strange. The C++11 standard supports detaching a thread, but we should not do it! The reason is that detaching a thread can be quite challenging. As rule, C.25 said:&nbsp;<a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rconc-detach\">CP.24: Think of an <code class=\"highlighter-rouge no-highlight\">thread<\/code> as a global container<\/a>. Of course, this means you are magnificent if you use only variables with global scope in the detached threads. NO!<\/p>\n<p>Even objects with static duration can be critical. For example, look at this small program with undefined behavior.<\/p>\n<div style=\"background: #f0f3f3; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007788; font-weight: bold;\">#include &lt;iostream&gt;<br \/>#include &lt;string&gt;<br \/>#include &lt;thread&gt;<br \/><br \/>void<\/span> <span style=\"color: #cc00ff;\">func<\/span>(){\r\n  std<span style=\"color: #555555;\">::<\/span>string s{<span style=\"color: #cc3300;\">\"C++11\"<\/span>};\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #006699; font-weight: bold;\">thread<\/span> t([<span style=\"color: #555555;\">&amp;s<\/span>]{ std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> s <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;});\r\n  t.detach();\r\n}<br \/><br \/>int main(){<br \/>  func();<br \/>}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>This is easy. The lambda function takes s by reference. This is undefined behavior because the child thread t uses the variable s, which goes out of scope. STOP! This is the apparent problem but the hidden issue is<span style=\"font-family: courier new, courier;\"> std::cout. std::cout<\/span><span style=\"font-family: courier new, courier;\"> <\/span>has a static duration. This means the lifetime of <span style=\"font-family: courier new, courier;\">std::cout<\/span> ends with the end of the program, and we have, additionally, a&nbsp;<a href=\"https:\/\/www.modernescpp.com\/index.php\/race-condition-versus-data-race\">race condition<\/a>: thread t may use <span style=\"font-family: courier new, courier;\">std::cout<\/span> at this time.&nbsp;<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>We are not yet done with the rules for concurrency in the C++ core guidelines. In the <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-the-remaining-rules-to-concurrency\">next post<\/a>, more rules will follow: they are about passing data to threads, sharing ownership between threads, and the costs of thread creation and destruction.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you create a new child thread, you must answer an important question: should you wait for the child or&nbsp;detach yourself from it? If you detach yourself from the newly created child, and your child uses variables that are bound to your life as creator a new question arises: Will the variables stay valid during [&hellip;]<\/p>\n","protected":false},"author":21,"featured_media":5439,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[],"class_list":["post-5440","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5440","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/users\/21"}],"replies":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/comments?post=5440"}],"version-history":[{"count":0,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5440\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5439"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5440"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5440"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5440"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}