{"id":5685,"date":"2019-05-24T07:33:37","date_gmt":"2019-05-24T07:33:37","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-std-array-and-std-vector-are-your-friends\/"},"modified":"2023-06-26T10:10:40","modified_gmt":"2023-06-26T10:10:40","slug":"c-core-guidelines-std-array-and-std-vector-are-your-friends","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-std-array-and-std-vector-are-your-friends\/","title":{"rendered":"C++ Core Guidelines: std::array and std::vector are your Friends"},"content":{"rendered":"<p>In 99 % of your use cases for a sequential container, you are outstanding with a <span style=\"font-family: courier new, courier;\">std::array<\/span> or a <span style=\"font-family: courier new, courier;\">std::vector.<\/span> What? If you don&#8217;t believe me, read this post.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5682\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280.png\" alt=\"rules 1752626 1280\" width=\"400\" height=\"400\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280.png 1280w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280-300x300.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280-1024x1024.png 1024w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280-150x150.png 150w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/rules-1752626_1280-768x768.png 768w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/p>\n<p>Okay, I can make it short today. Here is a rule of thumb: <strong> If you want to add elements to your container or remove elements from your container, use a <span style=\"font-family: courier new, courier;\">std::vector;<\/span> if not, use a<span style=\"font-family: courier new, courier;\"> std::array. <\/span><\/strong><\/p>\n<p>If you are busy, you can stop to read; if not, continue. <span style=\"font-family: courier new, courier;\"><\/span><\/p>\n<h2>The Details<\/h2>\n<p>Here is the reason for the rule of thumb from the guideline: <a href=\"http:\/\/isocpp.github.io\/CppCoreGuidelines\/CppCoreGuidelines#Rsl-vector\">SL.con.2: Prefer using STL <code class=\"highlighter-rouge no-highlight\">vector<\/code> by default, unless you have a reason to use a different container<\/a><\/p>\n<p><span style=\"font-family: courier new, courier;\">std::array<\/span> and <span style=\"font-family: courier new, courier;\">std::vector<\/span> offer the following advantages:<\/p>\n<ol>\n<li>the fastest general-purpose access (random access, including being vectorization-friendly);<\/li>\n<li>the fastest default access pattern (begin-to-end or end-to-begin is prefetcher-friendly);<\/li>\n<li>the lowest space overhead (contiguous layout has zero per-element overhead, which is cache-friendly).<\/li>\n<\/ol>\n<p>I already wrote in my last post<a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-the-standard-library\"> C++ Core Guidelines: The Standard Library<\/a>, about the third point. The first point of random access via the index operator is apparent. So, if you don&#8217;t like proof by authority, let me talk about the second point. To get the complete picture, here are the sequential containers of the STL.<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5683\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/sequentialOverview.png\" alt=\"sequentialOverview\" width=\"800\" height=\"370\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/sequentialOverview.png 865w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/sequentialOverview-300x139.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/sequentialOverview-768x355.png 768w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/p>\n<p>You see, we have five sequential containers in the standard template library. Depending on your use case, <span style=\"font-family: courier new, courier;\">std::vector<\/span>&nbsp;may be a 95% fit because you must often add or remove elements to your <span style=\"font-family: courier new, courier;\">std::vector<\/span>. Let me add a few additional remarks to the table.<\/p>\n<p>O(i) stands for an operation&#8217;s complexity (runtime). So O(1) means that the runtime of an operation on a container is constant and independent of the container&#8217;s size. On opposite to that, O(n) means that the runtime depends linearly on the number of elements of the container. What does that mean for a <span style=\"font-family: courier new, courier;\">std::vector <\/span>or a<span style=\"font-family: courier new, courier;\"> std::array.<\/span> The access time on an element is independent of the size of the <span style=\"font-family: courier new, courier;\">std::vector <\/span>or a<span style=\"font-family: courier new, courier;\"> std::array<\/span>, but the insertion or deletion of an arbitrary element with k-times more elements is k-times slower. Of course, the modification is only possible for a <span style=\"font-family: courier new, courier;\">std::vector<\/span>.<\/p>\n<p><span style=\"font-family: 'courier new', courier;\">std::array<\/span> and <span style=\"font-family: 'courier new', courier;\">std::vector<\/span> provide similar access time guarantees, but there is one big difference between them, which many developers ignore. The <span style=\"font-family: 'courier new', courier;\">std::array i<\/span>s typically created on the stack, and the elements of a&nbsp;<span style=\"font-family: 'courier new', courier;\">std::vector<\/span>&nbsp;are created on the heap. This means that a <span style=\"font-family: courier new, courier;\">std::array<\/span> can only have a limited number of elements, but a <span style=\"font-family: courier new, courier;\">std::vector<\/span> has infinite elements.<\/p>\n<p>Although the random access on the elements of a <span style=\"font-family: courier new, courier;\">std::vector<\/span> has the same complexity O(1) as the random access on the element of a <span style=\"font-family: courier new, courier;\">std::deque<\/span>, that doesn\u2019t mean that both operations are equally fast. I will come to this point later.<\/p>\n<p><span style=\"font-family: courier new, courier;\">std::vector<\/span> and <span style=\"font-family: courier new, courier;\">std::deque support<\/span> since C++11 the new method <span style=\"font-family: courier new, courier;\">shrink_to_fit<\/span>. The number of elements a <span style=\"font-family: courier new, courier;\">std::vector<\/span> or a <span style=\"font-family: courier new, courier;\">std:.deque<\/span> has (size) is usually smaller than the number of elements for which memory is already reserved (capacity). That is for a simple reason. The size of the <span style=\"font-family: courier new, courier;\">std::vector<\/span> or a <span style=\"font-family: courier new, courier;\">std::deque<\/span> can increase without an expensive allocation of new memory. The new method <span style=\"font-family: courier new, courier;\">shrink_to_fit<\/span> allows it to reduce the capacity of a <span style=\"font-family: courier new, courier;\">std::vector<\/span> a <span style=\"font-family: courier new, courier;\">std::deque<\/span> to its size. This call is not binding. That means the runtime can ignore it. But on popular platforms, I always observed the desired behavior.<\/p>\n<p>The complexity guarantee O(1) for the insertion or deletion into a double (<span style=\"font-family: courier new, courier;\">std::list<\/span>) or singly linked list (<span style=\"font-family: courier new, courier;\">std::forward_list<\/span>) is only guaranteed if the iterator points to the correct element. std::list and std::forward_list provide an exclusive guarantee, which may sometimes be necessary. When you modify a std::vector or a std::deque, the iterators become invalid. This will not hold for a <span style=\"font-family: courier new, courier;\">std::list<\/span> or a <span style=\"font-family: courier new, courier;\">std::forward::list<\/span>.<\/p>\n<p>You must have an excellent reason to use the very special <span style=\"font-family: courier new, courier;\">std::forward_list<\/span> as your sequential container. <span style=\"font-family: courier new, courier;\">std::forward_list<\/span> is optimized for memory requirements and performance and is applicable if the insertion, extraction, or movement of elements only affects adjacent elements. The reason for this special behavior is quite apparent. As a singly linked list, <span style=\"font-family: 'courier new', courier;\">std::forward_list<\/span> only supports a forward iterator and doesn&#8217;t know its size. This is the reason why you can not use a <span style=\"font-family: courier new, courier;\">std::forward_lis<\/span>t ist many algorithms of the STL.<\/p>\n<\/p>\n<h2>Memory Predictability<\/h2>\n<p>I said O(1) for the access time of an element in a <span style=\"font-family: courier new, courier;\">std::vector<\/span>, and an element in a <span style=\"font-family: courier new, courier;\">std::deque<\/span> does not mean the same. Here is my simple experiment, which I already provided in the post <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-the-remaining-rules-to-performance\">C++ Core Guidelines: The Remaining Rules to Performance<\/a>. This is the reason I make my explanation quite short.<\/p>\n<p>If you read an <span style=\"font-family: courier new, courier;\">int<\/span> from memory, more than the size of one <span style=\"font-family: courier new, courier;\">int<\/span> is read from memory. An entire cache line is read from memory and stored in a cache. On modern architectures, a cache line typically has 64 bytes. If you now request an additional variable from memory and this variable is in the previous cache, the read directly uses this cache, and the operation is much faster.<\/p>\n<p>Let&#8217;s see what this means for a <span style=\"font-family: courier new, courier;\">std::vector, a std::deque, std::list, and std::forward_list<\/span>. I intentionally ignore in my performance test a <span style=\"font-family: courier new, courier;\">std::array<\/span> because of its limited size.<\/p>\n<p>This was the theory of cache lines. Now I&#8217;m curious. Does it make a difference to read and accumulate all elements from <span style=\"font-family: courier\\ new, courier;\">std::vector, a std::deque, std::list, <span>and<\/span> std::forward_list<\/span>. The small program should answer.<\/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;\">\/\/ memoryAcess.cpp<\/span>\r\n\r\n<span style=\"color: #009999;\">#include &lt;forward_list&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;chrono&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;deque&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iomanip&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;list&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;vector&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;numeric&gt;<\/span>\r\n<span style=\"color: #009999;\">#include &lt;random&gt;<\/span>\r\n\r\n<span style=\"color: #006699; font-weight: bold;\">const<\/span> <span style=\"color: #007788; font-weight: bold;\">int<\/span> SIZE <span style=\"color: #555555;\">=<\/span> <span style=\"color: #ff6600;\">100<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span><span style=\"color: #aa0000; background-color: #ffaaaa;\">'<\/span><span style=\"color: #ff6600;\">000<\/span>; \r\n\r\n<span style=\"color: #006699; font-weight: bold;\">template<\/span> <span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #006699; font-weight: bold;\">typename<\/span> T<span style=\"color: #555555;\">&gt;<\/span>\r\n<span style=\"color: #007788; font-weight: bold;\">void<\/span> sumUp(T<span style=\"color: #555555;\">&amp;<\/span> t, <span style=\"color: #006699; font-weight: bold;\">const<\/span> std<span style=\"color: #555555;\">::<\/span>string<span style=\"color: #555555;\">&amp;<\/span> cont){            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (6)<\/span>\r\n  \r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>fixed <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>setprecision(<span style=\"color: #ff6600;\">10<\/span>);\r\n\r\n  <span style=\"color: #006699; font-weight: bold;\">auto<\/span> begin<span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>steady_clock<span style=\"color: #555555;\">::<\/span>now();\r\n  std<span style=\"color: #555555;\">::<\/span><span style=\"color: #007788; font-weight: bold;\">size_t<\/span> res <span style=\"color: #555555;\">=<\/span> std<span style=\"color: #555555;\">::<\/span>accumulate(t.begin(), t.end(), <span style=\"color: #ff6600;\">0LL<\/span>);\r\n  std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>duration<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">double<\/span><span style=\"color: #555555;\">&gt;<\/span> last<span style=\"color: #555555;\">=<\/span>  std<span style=\"color: #555555;\">::<\/span>chrono<span style=\"color: #555555;\">::<\/span>steady_clock<span style=\"color: #555555;\">::<\/span>now() <span style=\"color: #555555;\">-<\/span> begin;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> cont <span style=\"color: #555555;\">&lt;&lt;<\/span>  std<span style=\"color: #555555;\">::<\/span>endl;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"time: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> last.count() <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> <span style=\"color: #cc3300;\">\"res: \"<\/span> <span style=\"color: #555555;\">&lt;&lt;<\/span> res <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n \r\n  std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n     \r\n}\r\n\r\n<span style=\"color: #007788; font-weight: bold;\">int<\/span> main(){\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>cout <span style=\"color: #555555;\">&lt;&lt;<\/span> std<span style=\"color: #555555;\">::<\/span>endl;\r\n    \r\n    std<span style=\"color: #555555;\">::<\/span>random_device seed;                            <span style=\"color: #0099ff; font-style: italic;\">\/\/ (1)<\/span>\r\n    std<span style=\"color: #555555;\">::<\/span>mt19937 engine(seed());\r\n    std<span style=\"color: #555555;\">::<\/span>uniform_int_distribution<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> dist(<span style=\"color: #ff6600;\">0<\/span>, <span style=\"color: #ff6600;\">100<\/span>);\r\n    std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> randNumbers;\r\n    randNumbers.reserve(SIZE);\r\n    <span style=\"color: #006699; font-weight: bold;\">for<\/span> (<span style=\"color: #007788; font-weight: bold;\">int<\/span> i<span style=\"color: #555555;\">=<\/span><span style=\"color: #ff6600;\">0<\/span>; i <span style=\"color: #555555;\">&lt;<\/span> SIZE; <span style=\"color: #555555;\">++<\/span>i){\r\n        randNumbers.push_back(dist(engine));\r\n    }\r\n    \r\n    {\r\n      std<span style=\"color: #555555;\">::<\/span>vector<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span> myVec(randNumbers.begin(), randNumbers.end());\r\n      sumUp(myVec,<span style=\"color: #cc3300;\">\"std::vector&lt;int&gt;\"<\/span>);                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (2)<\/span>\r\n    }\r\n\r\n    \r\n    {\r\n      std<span style=\"color: #555555;\">::<\/span>deque<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>myDec(randNumbers.begin(), randNumbers.end());\r\n      sumUp(myDec,<span style=\"color: #cc3300;\">\"std::deque&lt;int&gt;\"<\/span>);                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (3)<\/span>\r\n    }\r\n    \r\n    {\r\n      std<span style=\"color: #555555;\">::<\/span>list<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>myList(randNumbers.begin(), randNumbers.end());\r\n      sumUp(myList,<span style=\"color: #cc3300;\">\"std::list&lt;int&gt;\"<\/span>);                 <span style=\"color: #0099ff; font-style: italic;\">\/\/ (4)<\/span>\r\n    }\r\n    \r\n    {\r\n      std<span style=\"color: #555555;\">::<\/span>forward_list<span style=\"color: #555555;\">&lt;<\/span><span style=\"color: #007788; font-weight: bold;\">int<\/span><span style=\"color: #555555;\">&gt;<\/span>myForwardList(randNumbers.begin(), randNumbers.end());\r\n      sumUp(myForwardList,<span style=\"color: #cc3300;\">\"std::forward_list&lt;int&gt;\"<\/span>);  <span style=\"color: #0099ff; font-style: italic;\">\/\/ (5)<\/span>\r\n    } \r\n    \r\n}\r\n<\/pre>\n<\/div>\n<p>&nbsp;<\/p>\n<p>The program <span style=\"font-family: courier\\ new, courier;\">memoryAccess.cpp<\/span> creates the first 100 Million random numbers between 0 and 100 (1). Then it accumulates the elements using a <span style=\"font-family: courier\\ new, courier;\">std::vector<\/span> (2), a <span style=\"font-family: courier\\ new, courier;\">std::deque<\/span> (3), a <span style=\"font-family: courier\\ new, courier;\">std::list<\/span> (4), and a <span style=\"font-family: courier\\ new, courier;\">std::forward_list<\/span> (5). The actual work is done in the function <span style=\"font-family: courier\\ new, courier;\">sumUp (<\/span>6).&nbsp;<\/p>\n<p>I compiled the program with maximum optimization and executed it on Linux and Windows. I&#8217;m not interested in the comparison between Linux and Windows because that would be a comparison between a desktop PC and a Laptop. I&#8217;m interested in the read performance of the four containers. Here it is:<img loading=\"lazy\" decoding=\"async\" class=\" alignright size-full wp-image-5422\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessWin.PNG\" alt=\"memoryAccessWin\" width=\"350\" height=\"519\" style=\"float: right;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessWin.PNG 505w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessWin-202x300.png 202w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" alignleft size-full wp-image-5423\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessLinux.png\" alt=\"memoryAccessLinux\" width=\"350\" height=\"515\" style=\"float: left;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessLinux.png 353w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2018\/04\/memoryAccessLinux-204x300.png 204w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>To make my performance comparison easy to digest, here is a graphic.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5684\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/performaneSequential.png\" alt=\"performaneSequential\" width=\"600\" height=\"450\" style=\"display: block; margin-left: auto; margin-right: auto;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/performaneSequential.png 640w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2019\/05\/performaneSequential-300x225.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/p>\n<p>I don&#8217;t want to overestimate these performance numbers, but one key observation is obvious. The more cache line aware the container is, the faster the access time of the elements: <span style=\"font-family: courier\\ new, courier;\"><strong>std::vector &gt; std::deque &gt; (std::list, std::forward_list).<\/strong><\/span><\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>I should write a similar post to the associative containers in the standard template library. From my perspective, they are underrepresented in the C++ core guidelines.&nbsp; My <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-core-guidelines-the-standard-library\">next post<\/a> is about associative containers such as<span style=\"font-family: courier new, courier;\"> std::map<\/span> and <span style=\"font-family: courier new, courier;\">std::unordered_map<\/span>.<\/p>\n<h2>&nbsp;<\/h2><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In 99 % of your use cases for a sequential container, you are outstanding with a std::array or a std::vector. What? If you don&#8217;t believe me, read this post.<\/p>\n","protected":false},"author":21,"featured_media":5682,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[372],"tags":[470],"class_list":["post-5685","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-modern-c","tag-performance"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5685","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=5685"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5685\/revisions"}],"predecessor-version":[{"id":6787,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5685\/revisions\/6787"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/5682"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5685"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5685"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5685"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}