{"id":40143,"date":"2004-03-22T07:00:00","date_gmt":"2004-03-22T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2004\/03\/22\/why-an-object-cannot-be-its-own-enumerator\/"},"modified":"2004-03-22T07:00:00","modified_gmt":"2004-03-22T07:00:00","slug":"why-an-object-cannot-be-its-own-enumerator","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20040322-00\/?p=40143","title":{"rendered":"Why an object cannot be its own enumerator"},"content":{"rendered":"<p>I&#8217;ve seen people using the following cheat when\nforced to implement an enumerator:<\/p>\n<pre>\nclass MyClass :\n  public IDataObject, public IEnumFORMATETC, ...\n{\n  ...\n  HRESULT EnumFormatEtc(DWORD dwDirection,\n                 IEnumFORMATETC** ppenumOut)\n  {\n    _dwDirection = dwDirection;\n    Reset();\n    *ppenumOut = this;\n    AddRef();\n    return S_OK;\n  }\n};\n<\/pre>\n<p>\nWhy create a separate enumerator object when you can\njust be your own enumerator?  It&#8217;s so much easier.\n<\/p>\n<p>\nAnd it&#8217;s wrong.\n<\/p>\n<p>\nConsider what happens if two people try to enumerate\nyour formats at the same time:  The two enumerators\nare really the same enumerator, so operations on one\nwill interfere with the other.\nFor example, consider this odd code fragment\n(error checking deleted for expository purposes)\nwhich looks to see if the data object exposes\nthe same data under multiple aspects:\n<\/p>\n<pre>\nIDataObject *pdto = &lt;MyClass instance&gt;;\n\/\/ Obtain two enumerators since we will run\n\/\/ each one independently.\nIEnumFORMATETC* penum1;\nIEnumFORMATETC* penum2;\npdto-&gt;EnumFormatEtc(DATADIR_GET, &amp;penum1);\npdto-&gt;EnumFormatEtc(DATADIR_GET, &amp;penum2);\nFORMATETC fe1, fe2;\nwhile (penum1-&gt;Next(1, &amp;fe1, NULL) == S_OK) {\n  penum2-&gt;Reset(); \/\/ start a new pass\n  while (penum2-&gt;Next(1, &amp;fe2, NULL) == S_OK) {\n    if (fe1.cfFormat == fe2.cfFormat &amp;&amp;\n        cf1.dwAspect != cf2.dwAspect) {\n        \/\/ found it!\n    }\n  }\n}\npenum1-&gt;Release();\npenum2-&gt;Release();\n<\/pre>\n<p>\nWhen the code does a <code>penum2-&gt;Reset()<\/code>, this also\ninadvertently resets the first enumerator.\nThe loop runs through penum2 (which therefore also\nruns through penum1), and when it&#8217;s done, the enumerator\nis left at the end of the list.\n<\/p>\n<p>\nThen we loop back and call <code>penum1-&gt;Next()<\/code>,\nwhich immediately returns failure since the inner loop\nran it to completion.\n<\/p>\n<p>Result: The loop fails to find anything\nbecause the second enumerator corrupted the first.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;ve seen people using the following cheat when forced to implement an enumerator: class MyClass : public IDataObject, public IEnumFORMATETC, &#8230; { &#8230; HRESULT EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumOut) { _dwDirection = dwDirection; Reset(); *ppenumOut = this; AddRef(); return S_OK; } }; Why create a separate enumerator object when you can just be your own enumerator? [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-40143","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>I&#8217;ve seen people using the following cheat when forced to implement an enumerator: class MyClass : public IDataObject, public IEnumFORMATETC, &#8230; { &#8230; HRESULT EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC** ppenumOut) { _dwDirection = dwDirection; Reset(); *ppenumOut = this; AddRef(); return S_OK; } }; Why create a separate enumerator object when you can just be your own enumerator? [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40143","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=40143"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/40143\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=40143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=40143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=40143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}