{"id":5244,"date":"2017-04-16T20:28:11","date_gmt":"2017-04-16T20:28:11","guid":{"rendered":"https:\/\/www.modernescpp.com\/index.php\/c-17-avoid-copying-with-std-string-view\/"},"modified":"2023-06-26T12:18:13","modified_gmt":"2023-06-26T12:18:13","slug":"c-17-avoid-copying-with-std-string-view","status":"publish","type":"post","link":"https:\/\/www.modernescpp.com\/index.php\/c-17-avoid-copying-with-std-string-view\/","title":{"rendered":"C++17 &#8211; Avoid Copying with std::string_view"},"content":{"rendered":"<p>The purpose of <span style=\"font-family: courier new,courier;\">std::string_view<\/span> is to avoid copying data already owned by someone else and of which only a non-mutating view is required. So, this post is mainly about performance.<\/p>\n<p><!--more--><\/p>\n<p>&nbsp;<\/p>\n<p>Today,&nbsp; I write about a main feature of C++17.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-4724\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2016\/04\/timeline.png\" alt=\"timeline\" width=\"700\" height=\"338\" style=\"margin: 15px;\" \/><\/p>\n<p>I assume that you know a little bit about <span style=\"font-family: courier new,courier;\">std::string_view.<\/span> If not, read the previous post<a href=\"https:\/\/www.modernescpp.com\/index.php\/c-17-what-s-new-in-the-library\"> C++17 &#8211; What&#8217;s New in the library<\/a> first. A C++ string is like a thin wrapper storing data on the heap. Therefore, a memory allocation often kicks in when you deal with C and C++ strings. Let&#8217;s have a look.<\/p>\n<h2>Small string optimization<\/h2>\n<p>You will see in a few lines why I called this paragraph small string optimization.<\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ sso.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n\r\n<span style=\"color: #2b91af;\">void<\/span>* <span style=\"color: #0000ff;\">operator<\/span> new(std::<span style=\"color: #2b91af;\">size_t<\/span> count){\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"   \"<\/span> &lt;&lt; count &lt;&lt; <span style=\"color: #a31515;\">\" bytes\"<\/span> &lt;&lt; std::endl;\r\n    <span style=\"color: #0000ff;\">return<\/span> malloc(count);\r\n}\r\n\r\n<span style=\"color: #2b91af;\">void<\/span> getString(<span style=\"color: #0000ff;\">const<\/span> std::string&amp; str){}\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main() {\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"std::string\"<\/span> &lt;&lt; std::endl;\r\n\r\n    std::string small = <span style=\"color: #a31515;\">\"0123456789\"<\/span>;\r\n    std::string substr = small.substr(5);\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"   \"<\/span> &lt;&lt; substr &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"getString\"<\/span> &lt;&lt; std::endl;\r\n\r\n    getString(small);\r\n    getString(<span style=\"color: #a31515;\">\"0123456789\"<\/span>);\r\n    <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">char<\/span> message []= <span style=\"color: #a31515;\">\"0123456789\"<\/span>;\r\n    getString(message);\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>I overloaded the global <span style=\"font-family: courier new,courier;\">operator new<\/span> in lines 6-9. Therefore, you can see which operation causes a memory allocation. Come on. That&#8217;s easy. Lines 19, 20, 28, and 29 cause a memory allocation. Here you have the numbers:<\/p>\n<p>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5239\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/sso.png\" alt=\"sso\" style=\"margin: 15px;\" width=\"380\" height=\"190\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/sso.png 380w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/sso-300x150.png 300w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><\/p>\n<p>What the &#8230;? I said. The strings store their data on the heap. But that is only true if the string exceeds an implementation-dependent size. This size for <span style=\"font-family: courier new,courier;\">std::string<\/span> is 15 for MSVC and GCC and 23 for Clang.<\/p>\n<p>That means, on the contrary, small strings are stored directly in the string object. Therefore, no memory allocation is required.<\/p>\n<p>From now on, my strings will always have at least 30 characters. So, I do have not to reason about small string optimization. Let&#8217;s start once more but this time with longer strings.<\/p>\n<\/p>\n<h2>No memory allocation required<\/h2>\n<p>Now,<span style=\"font-family: courier new,courier;\"> std::string_view<\/span> shines brightly. Contrary to<span style=\"font-family: courier new,courier;\"> std::string<\/span>, <span style=\"font-family: courier new,courier;\">std::string_view<\/span> allocates no memory. Here is the proof.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ stringView.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;cassert&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;string_view&gt;<\/span>\r\n\r\n<span style=\"color: #2b91af;\">void<\/span>* <span style=\"color: #0000ff;\">operator<\/span> new(std::<span style=\"color: #2b91af;\">size_t<\/span> count){\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"   \"<\/span> &lt;&lt; count &lt;&lt; <span style=\"color: #a31515;\">\" bytes\"<\/span> &lt;&lt; std::endl;\r\n    <span style=\"color: #0000ff;\">return<\/span> malloc(count);\r\n}\r\n\r\n<span style=\"color: #2b91af;\">void<\/span> getString(<span style=\"color: #0000ff;\">const<\/span> std::string&amp; str){}\r\n\r\n<span style=\"color: #2b91af;\">void<\/span> getStringView(std::string_view strView){}\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main() {\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"std::string\"<\/span> &lt;&lt; std::endl;\r\n\r\n    std::string large = <span style=\"color: #a31515;\">\"0123456789-123456789-123456789-123456789\"<\/span>;\r\n    std::string substr = large.substr(10);\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"std::string_view\"<\/span> &lt;&lt; std::endl;\r\n\r\n    std::string_view largeStringView{large.c_str(), large.size()};\r\n    largeStringView.remove_prefix(10);\r\n\r\n    assert(substr == largeStringView);\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"getString\"<\/span> &lt;&lt; std::endl;\r\n\r\n    getString(large);\r\n    getString(<span style=\"color: #a31515;\">\"0123456789-123456789-123456789-123456789\"<\/span>);\r\n    <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">char<\/span> message []= <span style=\"color: #a31515;\">\"0123456789-123456789-123456789-123456789\"<\/span>;\r\n    getString(message);\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"getStringView\"<\/span> &lt;&lt; std::endl;\r\n\r\n    getStringView(large);\r\n    getStringView(<span style=\"color: #a31515;\">\"0123456789-123456789-123456789-123456789\"<\/span>);\r\n    getStringView(message);\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Once more. Memory allocations occur in lines 24, 25, 41, and 43. But what happens in the corresponding calls in lines 31, 32, 50, and 51? No memory allocation!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5240\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/stringView.png\" alt=\"stringView\" style=\"margin: 15px;\" width=\"383\" height=\"293\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/stringView.png 383w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/stringView-300x230.png 300w\" sizes=\"auto, (max-width: 383px) 100vw, 383px\" \/><\/p>\n<p>That is impressive. You can imagine this is a performance boost because memory allocation is costly. You can observe this performance boost very well if you build substrings of existing strings.<\/p>\n<h2>O(n) versus O(1)<\/h2>\n<p><span style=\"font-family: courier new,courier;\">std::string<\/span> and <span style=\"font-family: courier new,courier;\">std::string_view<\/span> have both a method <span style=\"font-family: courier new,courier;\">substr.<\/span> The method of the <span style=\"font-family: courier new,courier;\">std::string <\/span>returns a substring, but the method of the <span style=\"font-family: courier new,courier;\">std::string_view <\/span>returns a view of a substring. This sounds not so thrilling. But there is a big difference between both methods. <span style=\"font-family: courier new,courier;\">std::string::substr<\/span> has linear complexity. <span style=\"font-family: courier new,courier;\">std::string_view::substr<\/span> has constant complexity. That means that the performance of the operation on the <span style=\"font-family: courier new,courier;\">std::string<\/span> is directly dependent on the size of the substring, but the performance of the operation on the <span style=\"font-family: courier new,courier;\">std::string_view<\/span> is independent of the size of the substring.<\/p>\n<p>Now I&#8217;m curious. Let&#8217;s make a simple performance comparison.<\/p>\n<p>&nbsp;<\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; gray;border-width: .1em .1em .1em .8em;\">\n<table>\n<tbody>\n<tr>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"> 1\r\n 2\r\n 3\r\n 4\r\n 5\r\n 6\r\n 7\r\n 8\r\n 9\r\n10\r\n11\r\n12\r\n13\r\n14\r\n15\r\n16\r\n17\r\n18\r\n19\r\n20\r\n21\r\n22\r\n23\r\n24\r\n25\r\n26\r\n27\r\n28\r\n29\r\n30\r\n31\r\n32\r\n33\r\n34\r\n35\r\n36\r\n37\r\n38\r\n39\r\n40\r\n41\r\n42\r\n43\r\n44\r\n45\r\n46\r\n47\r\n48\r\n49\r\n50\r\n51\r\n52\r\n53\r\n54\r\n55\r\n56\r\n57\r\n58\r\n59<\/pre>\n<\/td>\n<td>\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008000;\">\/\/ substr.cpp<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;chrono&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;fstream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;iostream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;random&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;sstream&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;string&gt;<\/span>\r\n<span style=\"color: #0000ff;\">#include &lt;vector&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">#include &lt;string_view&gt;<\/span>\r\n\r\n<span style=\"color: #0000ff;\">static<\/span> <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">int<\/span> count = 30;\r\n<span style=\"color: #0000ff;\">static<\/span> <span style=\"color: #0000ff;\">const<\/span> <span style=\"color: #2b91af;\">int<\/span> access = 10000000;\r\n\r\n<span style=\"color: #2b91af;\">int<\/span> main(){\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::ifstream inFile(<span style=\"color: #a31515;\">\"grimm.txt\"<\/span>);\r\n\r\n    std::stringstream strStream;\r\n    strStream &lt;&lt;  inFile.rdbuf();\r\n    std::string grimmsTales = strStream.str();\r\n\r\n    <span style=\"color: #2b91af;\">size_t<\/span> size = grimmsTales.size();\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"Grimms' Fairy Tales size: \"<\/span> &lt;&lt; size &lt;&lt; std::endl;\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    <span style=\"color: #008000;\">\/\/ random values<\/span>\r\n    std::random_device seed;\r\n    std::mt19937 engine(seed());\r\n    std::uniform_int_distribution&lt;&gt; uniformDist(0, size - count - 2);\r\n    std::vector&lt;<span style=\"color: #2b91af;\">int<\/span>&gt; randValues;\r\n    <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #0000ff;\">auto<\/span> i = 0; i &lt;  access; ++i) randValues.push_back(uniformDist(engine));\r\n\r\n    <span style=\"color: #0000ff;\">auto<\/span> start = std::chrono::steady_clock::now();\r\n    <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #0000ff;\">auto<\/span> i = 0; i  &lt; access; ++i ) {\r\n        grimmsTales.substr(randValues[i], count);\r\n    }\r\n    std::chrono::duration&lt;<span style=\"color: #2b91af;\">double<\/span>&gt; durString= std::chrono::steady_clock::now() - start;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"std::string::substr:      \"<\/span> &lt;&lt; durString.count() &lt;&lt; <span style=\"color: #a31515;\">\" seconds\"<\/span> &lt;&lt; std::endl;\r\n\r\n    std::string_view grimmsTalesView{grimmsTales.c_str(), size};\r\n    start = std::chrono::steady_clock::now();\r\n    <span style=\"color: #0000ff;\">for<\/span> (<span style=\"color: #0000ff;\">auto<\/span> i = 0; i  &lt; access; ++i ) {\r\n        grimmsTalesView.substr(randValues[i], count);\r\n    }\r\n    std::chrono::duration&lt;<span style=\"color: #2b91af;\">double<\/span>&gt; durStringView= std::chrono::steady_clock::now() - start;\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"std::string_view::substr: \"<\/span> &lt;&lt; durStringView.count() &lt;&lt; <span style=\"color: #a31515;\">\" seconds\"<\/span> &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; <span style=\"color: #a31515;\">\"durString.count()\/durStringView.count(): \"<\/span> &lt;&lt; durString.count()\/durStringView.count() &lt;&lt; std::endl;\r\n\r\n    std::cout &lt;&lt; std::endl;\r\n\r\n}\r\n<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<p>&nbsp;<\/p>\n<p>Before I present the numbers, let me say a few words about my performance test. The key idea of the performance test is to read in a large file as a <span style=\"font-family: courier new,courier;\">std::string<\/span> <span style=\"font-family: courier new,courier;\"><\/span>and create a lot of substrings with <span style=\"font-family: courier new,courier;\">std::string<\/span> and <span style=\"font-family: courier new,courier;\">std::string_view<\/span>. I&#8217;m precisely interested in how long this creation of substrings will take.<\/p>\n<p>I used &#8220;Grimm&#8217;s Fairy Tales&#8221; as my long file. What else should I use? The string <span style=\"font-family: courier new,courier;\">grimmTales<\/span> (line 24) has the content of the file. I fill the <span style=\"font-family: courier new,courier;\">std::vector&lt;int&gt;<\/span> in line 37 with <span style=\"font-family: courier new,courier;\">access<\/span> number (10&#8217;000&#8217;000) of values in the range [0, size &#8211; count &#8211; 2] (line 34). Now the performance test starts. I create in lines 39 to 41 <span style=\"font-family: courier new,courier;\">access<\/span> substrings of the fixed-length <span style=\"font-family: courier new,courier;\">count. <\/span>The <span style=\"font-family: courier new,courier;\">count <\/span>is 30. Therefore, no small string optimization kicks in. I do the same in lines 47 to 49 with the <span style=\"font-family: courier new,courier;\">std::string_view. <\/span><\/p>\n<p>Here are the numbers. You see the length of the file, the numbers for <span style=\"font-family: courier new,courier;\">std::string::substr<\/span> and <span style=\"font-family: courier new,courier;\">std::string_view::substr,<\/span> and the ratio between both. I used GCC 6.3.0 as the compiler.<\/p>\n<h3>Size 30<\/h3>\n<p>Only out of curiosity. The numbers without optimization.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5241\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substr.png\" alt=\"substr\" style=\"margin: 15px;\" width=\"543\" height=\"221\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substr.png 543w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substr-300x122.png 300w\" sizes=\"auto, (max-width: 543px) 100vw, 543px\" \/><\/p>\n<p>But now to the more critical numbers. GCC with complete optimization.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5242\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substrOptimized.png\" alt=\"substrOptimized\" width=\"543\" height=\"221\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substrOptimized.png 543w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/substrOptimized-300x122.png 300w\" sizes=\"auto, (max-width: 543px) 100vw, 543px\" \/><\/p>\n<p>&nbsp;<\/p>\n<p>The optimization makes no big difference in the case of <span style=\"font-family: courier new,courier;\">std::string<\/span> but a significant difference in the case of <span style=\"font-family: courier new,courier;\">std::string_view<\/span>.&nbsp; Making a substring with <span style=\"font-family: courier new,courier;\">std::string_view<\/span> is about 45 times faster than using <span style=\"font-family: courier new,courier;\">std::string<\/span>. If that is not a reason to use<span style=\"font-family: courier new,courier;\"> std::string_view?<\/span>&nbsp;<\/p>\n<h3>Different sizes<\/h3>\n<p>Now I&#8217;m becoming more curious. What will happen if I play with the size <span style=\"font-family: courier new,courier;\">count<\/span> of the substring? Of course, all numbers are with maximum optimization. I rounded them to the 3rd decimal place.<\/p>\n<h2>&nbsp;<img loading=\"lazy\" decoding=\"async\" class=\" size-full wp-image-5243\" src=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/numbers.png\" alt=\"numbers\" width=\"600\" height=\"235\" style=\"margin: 15px;\" srcset=\"https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/numbers.png 831w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/numbers-300x117.png 300w, https:\/\/www.modernescpp.com\/wp-content\/uploads\/2017\/04\/numbers-768x300.png 768w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/h2>\n<p>&nbsp;<\/p>\n<p>I&#8217;m not astonished; the numbers reflect the complexity guarantees of <span style=\"font-family: courier new,courier;\">std::string::substr<\/span> versus <span style=\"font-family: courier new,courier;\">std::string_view::substr<\/span>. The complexity of the first is linearly dependent on the substring&#8217;s size; the second is independent of the size of the substring. In the end, the <span style=\"font-family: courier new,courier;\">std::string_view<\/span> drastically outperforms <span style=\"font-family: courier new,courier;\">std::string<\/span>.<\/p>\n<h2>What&#8217;s next?<\/h2>\n<p>There is more to write about <span style=\"font-family: courier new,courier;\">std::any<\/span>, <span style=\"font-family: courier new,courier;\">std::optional<\/span>, and <span style=\"font-family: courier new,courier;\">std::variant<\/span>. Wait for the <a href=\"https:\/\/www.modernescpp.com\/index.php\/c-17-constructed-in-place\">next post<\/a>.<\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The purpose of std::string_view is to avoid copying data already owned by someone else and of which only a non-mutating view is required. So, this post is mainly about performance.<\/p>\n","protected":false},"author":21,"featured_media":4724,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[370],"tags":[463],"class_list":["post-5244","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-c-17","tag-string"],"_links":{"self":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5244","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=5244"}],"version-history":[{"count":1,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5244\/revisions"}],"predecessor-version":[{"id":6875,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/posts\/5244\/revisions\/6875"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media\/4724"}],"wp:attachment":[{"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/media?parent=5244"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/categories?post=5244"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.modernescpp.com\/index.php\/wp-json\/wp\/v2\/tags?post=5244"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}