{"id":20935,"date":"2018-10-04T08:34:25","date_gmt":"2018-10-04T08:34:25","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/vcblog\/?p=20935"},"modified":"2022-06-23T19:50:40","modified_gmt":"2022-06-23T19:50:40","slug":"stdany-how-when-and-why","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cppblog\/stdany-how-when-and-why\/","title":{"rendered":"std::any: How, when, and why"},"content":{"rendered":"<p><i>This post is part of a <\/i><a href=\"https:\/\/blogs.msdn.microsoft.com\/vcblog\/category\/c-qa-series\/\"><i>regular series of posts<\/i><\/a><i> where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: MSVC toolset, the standard language and library, the C++ standards committee, isocpp.org, <\/i><i>CppCon<\/i><i>, etc. Today\u2019s post is by Casey Carter.<\/i><\/p>\n<p>C++17 adds several new &#8220;vocabulary types&#8221; &#8211; types intended to be used in the interfaces between components from different sources &#8211; to the standard library. <a href=\"https:\/\/devblogs.microsoft.com\/vcblog\/\/07\/msvc-the-best-choice-for-windows\/\">MSVC<\/a> has been shipping implementations of <code>std::optional<\/code>, <code>std::any<\/code>, and <code>std::variant<\/code>since the Visual Studio 2017 release, but we haven&#8217;t provided any guidelines on how and when these vocabulary types should be used. This article on <code>std::any<\/code> is the second of a series that examines each of the vocabulary types in turn.<\/p>\n<h3>Storing arbitrary user data<\/h3>\n<p>Say you&#8217;re creating a calendar component that you intend to distribute in a library for use by other programmers. You want your calendar to be usable for solving a wide array of problems, so you decide you need a mechanism to associate arbitrary client data with days\/weeks\/months\/years. How do you best implement this extensibility design requirement?<\/p>\n<p>A C programmer might add a <code>void*<\/code> to each appropriate data structure:<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\">struct day { \r\n  \/\/ ...things... \r\n  void* user_data; \r\n}; \r\n\r\nstruct month { \r\n  std::vector&lt;day&gt; days; \r\n  void* user_data; \r\n};\r\n<\/pre>\n<p>and suggest that clients hang whatever data they like from it. This solution has a few immediately apparent shortcomings:<\/p>\n<ul>\n<li>You can always cast a <code>void*<\/code> to a <code>Foo*<\/code> whether or not the object it points at is actually a <code>Foo<\/code>. The lack of type information for the associated data means that the library can&#8217;t provide even a basic level of type safety by guaranteeing that later accesses to stored data use the same type as was stored originally:\n<pre>some_day.user_data = new std::string{\"Hello, World!\"}; \r\n\/\/ \u2026much later \r\nFoo* some_foo = static_cast&lt;Foo*&gt;(some_day.user_data); \r\nsome_foo-&gt;frobnicate(); \/\/ BOOM!\r\n<\/pre>\n<\/li>\n<li><code>void*<\/code> doesn&#8217;t manage lifetime like a smart pointer would, so clients must manage the lifetime of the associated data manually. Mistakes result in memory leaks:\n<pre>delete some_day.user_data; \r\nsome_day.user_data = nullptr; \r\nsome_month.days.clear(); \/\/ Oops: hopefully none of these days had \r\n                         \/\/ non-null user_data\r\n<\/pre>\n<\/li>\n<li>The library cannot copy the object that a <code>void*<\/code> points at since it doesn\u2019t know that object\u2019s type. For example, if your library provides facilities to copy annotations from one week to another, clients must copy the associated data manually. As was the case with manual lifetime management, mistakes are likely to result in dangling pointers, double frees, or leaks:\n<pre>some_month.days[0] = some_month.days[1]; \r\nif (some_month.days[1].user_data) { \r\n  \/\/ I'm storing strings in user_data, and don't want them shared \r\n  \/\/ between days. Copy manually: \r\n  std::string const&amp; src = *some_month.days[1].user_data; \r\n  some_month.days[0].user_data = new std::string(src); \r\n}\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>The C++ Standard Library provides us with at least one tool that can help: <code>shared_ptr&lt;void&gt;<\/code>. Replacing the <code>void*<\/code> with <code>shared_ptr&lt;void&gt;<\/code> solves the problem of lifetime management:<\/p>\n<pre>struct day {\r\n  \/\/ ...things...\r\n  std::shared_ptr&lt;void&gt; user_data;\r\n};\r\n\r\nstruct month {\r\n  std::vector&lt;day&gt; days;\r\n  std::shared_ptr&lt;void&gt; user_data;\r\n};\r\n<\/pre>\n<p>since <code>shared_ptr<\/code> squirrels away enough type info to know how to properly destroy the object it points at. A client could create a <code>shared_ptr&lt;Foo&gt;<\/code>, and the deleter would continue to work just fine after converting to <code>shared_ptr&lt;void&gt;<\/code> for storage in the calendar:<\/p>\n<pre>some_day.user_data = std::make_shared&lt;std::string&gt;(\"Hello, world!\");\r\n\/\/ ...much later...\r\nsome_day = some_other_day; \/\/ the object at which some_day.user_data _was_\r\n                           \/\/ pointing is freed automatically\r\n<\/pre>\n<p>This solution may help solve the copyability problem as well, if the client is happy to have multiple days\/weeks\/etc. hold copies of the same <code>shared_ptr&lt;void&gt;<\/code> &#8211; denoting a single object &#8211; rather than independent values. <code>shared_ptr<\/code> doesn\u2019t help with the primary problem of type-safety, however. Just as with <code>void*<\/code>, <code>shared_ptr&lt;void&gt;<\/code> provides no help tracking the proper type for associated data. Using a <code>shared_ptr<\/code> instead of a <code>void*<\/code> also makes it impossible for clients to &#8220;hack the system&#8221; to avoid memory allocation by reinterpreting integral values as <code>void*<\/code> and storing them directly; using <code>shared_ptr<\/code> forces us to allocate memory even for tiny objects like <code>int<\/code>.<\/p>\n<h3>Not just <code style=\"font-size: x-large;\">any<\/code> solution will do<\/h3>\n<p><code>std::any<\/code> is the smarter <code>void*<\/code>\/<code>shared_ptr&lt;void&gt;<\/code>. You can initialize an <code>any<\/code> with a value of any copyable type:<\/p>\n<pre>std::any a0; \r\nstd::any a1 = 42; \r\nstd::any a2 = month{\"October\"};\r\n<\/pre>\n<p>Like <code>shared_ptr<\/code>, <code>any<\/code> remembers how to destroy the contained value for you when the <code>any<\/code> object is destroyed. Unlike <code>shared_ptr<\/code>, <code>any<\/code> also remembers how to <i>copy<\/i> the contained value and does so when the <code>any<\/code> object is copied:<\/p>\n<pre>std::any a3 = a0; \/\/ Copies the empty any from the previous snippet\r\nstd::any a4 = a1; \/\/ Copies the \"int\"-containing any\r\na4 = a0;          \/\/ copy assignment works, and properly destroys the old value\r\n<\/pre>\n<p>Unlike <code>shared_ptr<\/code>, <code>any<\/code> knows what type it contains:<\/p>\n<pre>assert(!a0.has_value());            \/\/ a0 is still empty\r\nassert(a1.type() == typeid(int));\r\nassert(a2.type() == typeid(month));\r\nassert(a4.type() == typeid(void));  \/\/ type() returns typeid(void) when empty\r\n<\/pre>\n<p>and uses that knowledge to ensure that when you access the contained value &#8211; for example, by obtaining a reference with <code>any_cast<\/code> &#8211; you access it with the correct type:<\/p>\n<pre>assert(std::any_cast&lt;int&amp;&gt;(a1) == 42);             \/\/ succeeds\r\nstd::string str = std::any_cast&lt;std::string&amp;&gt;(a1); \/\/ throws bad_any_cast since\r\n                                                   \/\/ a1 holds int, not string\r\nassert(std::any_cast&lt;month&amp;&gt;(a2).days.size() == 0);\r\nstd::any_cast&lt;month&amp;&gt;(a2).days.push_back(some_day);\r\n<\/pre>\n<p>If you want to avoid exceptions in a particular code sequence and you are uncertain what type an <code>any<\/code> contains, you can perform a combined type query and access with the pointer overload of <code>any_cast<\/code>:<\/p>\n<pre>if (auto ptr = std::any_cast&lt;int&gt;(&amp;a1)) {\r\n  assert(*ptr == 42); \/\/ runs since a1 contains an int, and succeeds\r\n}\r\nif (auto ptr = std::any_cast&lt;std::string&gt;(&amp;a1)) {\r\n  assert(false);      \/\/ never runs: any_cast returns nullptr since\r\n                      \/\/ a1 doesn't contain a string\r\n}\r\n<\/pre>\n<p>The C++ Standard encourages implementations to store small objects with non-throwing move constructors directly in the storage of the <code>any<\/code> object, avoiding the costs of dynamic allocation. This feature is best-effort and there\u2019s no guaranteed threshold below which <code>any<\/code> is portably guaranteed not to allocate. In practice, the Visual C++ implementation uses a larger <code>any<\/code> that avoids allocation for object types with non-throwing moves up to a handful of pointers in size, whereas libc++ and libstdc++ allocate for objects that are two or more pointers in size (See <a href=\"https:\/\/godbolt.org\/z\/RQd_w5\">https:\/\/godbolt.org\/z\/RQd_w5<\/a>).<\/p>\n<h3>How to select a vocabulary type (aka \u201cWhat if you know the type(s) to be stored?\u201d)<\/h3>\n<p>If you have knowledge about the type(s) being stored &#8211; beyond the fact that the types being stored must be copyable &#8211; then <code>std::any<\/code> is probably not the proper tool: its flexibility has performance costs. If there is exactly one such type <code>T<\/code>, you should reach for <code><a href=\"https:\/\/blogs.msdn.microsoft.com\/vcblog\/2018\/09\/04\/stdoptional-how-when-and-why\/\">std::optional<\/a><\/code>. If the types to store will always be function objects with a particular signature &#8211; callbacks, for example &#8211; you want <code>std::function<\/code>. If you only need to store types from some set fixed at compile time, <code>std::variant<\/code> is a good choice; but let&#8217;s not get ahead of ourselves &#8211; that will be the next article.<\/p>\n<h2>Conclusions<\/h2>\n<p>When you need to store an object of an arbitrary type, pull <code>std::any<\/code> out of your toolbox. Be aware that there are probably more appropriate tools available when you do know something about the type to be stored.<\/p>\n<p>If you have any questions (Get it? &#8220;any&#8221; questions?), please feel free to post in the comments below. You can also send any comments and suggestions directly to the author via e-mail at <a href=\"mailto:cacarter@microsoft.com\">cacarter@microsoft.com<\/a>, or Twitter <a href=\"https:\/\/twitter.com\/CoderCasey\">@CoderCasey<\/a>. Thank you!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is part of a regular series of posts where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: MSVC toolset, the standard language and library, the C++ standards committee, isocpp.org, CppCon, etc. Today\u2019s post is by Casey [&hellip;]<\/p>\n","protected":false},"author":1529,"featured_media":35994,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[512],"tags":[],"class_list":["post-20935","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general-cpp-series"],"acf":[],"blog_post_summary":"<p>This post is part of a regular series of posts where the C++ product team here at Microsoft and other guests answer questions we have received from customers. The questions can be about anything C++ related: MSVC toolset, the standard language and library, the C++ standards committee, isocpp.org, CppCon, etc. Today\u2019s post is by Casey [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20935","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/users\/1529"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/comments?post=20935"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/posts\/20935\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media\/35994"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/media?parent=20935"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/categories?post=20935"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cppblog\/wp-json\/wp\/v2\/tags?post=20935"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}