{"id":18536303,"url":"https://github.com/adishavit/ctad_for_unique_ptr","last_synced_at":"2025-05-15T00:35:37.680Z","repository":{"id":72816287,"uuid":"116647880","full_name":"adishavit/ctad_for_unique_ptr","owner":"adishavit","description":"A proposal to add Class Template Argument Deduction for C++ unique_ptr when a custom deleter is specified.","archived":false,"fork":false,"pushed_at":"2018-01-08T19:48:52.000Z","size":4,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-26T03:27:25.772Z","etag":null,"topics":["cpp-library","cpp20","proposal"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/adishavit.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-08T08:06:28.000Z","updated_at":"2022-05-03T14:11:52.000Z","dependencies_parsed_at":"2023-06-06T05:00:40.761Z","dependency_job_id":null,"html_url":"https://github.com/adishavit/ctad_for_unique_ptr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adishavit%2Fctad_for_unique_ptr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adishavit%2Fctad_for_unique_ptr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adishavit%2Fctad_for_unique_ptr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/adishavit%2Fctad_for_unique_ptr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/adishavit","download_url":"https://codeload.github.com/adishavit/ctad_for_unique_ptr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239251183,"owners_count":19607583,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp-library","cpp20","proposal"],"created_at":"2024-11-06T19:31:50.345Z","updated_at":"2025-02-17T07:28:44.316Z","avatar_url":"https://github.com/adishavit.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"*Document number: --   \nDate: 2018-??-??    \nAudience: Library Working Group   \nReply-To: Adi Shavit `\u003cmy-email\u003e`*  \n\n---\n\n# Allowing CTAD for `unique_ptr` with Custom Deleter\n\n## Motivation\n\nConsider the following example:\n```\nstd::unique_ptr\u003cHANDLE, decltype(CloseHandle)\u003e fh0{ CreateFile(...), CloseHandle }; // this is okay\nstd::unique_ptr fh1{ CreateFile(...), CloseHandle };                                // this is ill-formed\n```\n\nThe second expression is ill-formed due to the wording in [**[unique.ptr.single.ctor]/16**](http://eel.is/c++draft/unique.ptr#single.ctor-16):  \n\n\u003e *Remarks:* If class template argument deduction ([over.match.class.deduct]) would select a function template corresponding to either of these constructors, then the program is ill-formed.\n\nbut the first expression is fine because the `unique_ptr` the class template arguments are specified explicitly.  \nThe type `HANDLE` of the return value of `CreateFile()` must be explicitely specified *and* the deleter must be mentioned twice, once with `decltype()` and once when passed as the 2nd constructor argument - the custom deleter.     \n\nWhen used with lambdas the code is even more verbose. Consider the following example:  \n\n```\nauto rel_img = [](IplImage* p){ ::cvReleaseImage(\u0026p); };                                // must name lambda\nstd::unique_ptr\u003cIplImage, decltype(rel_img)\u003e img0{ ::cvCreateImage(...), rel_img };     // this is okay  \nstd::unique_ptr img1{ ::cvCreateImage(...), [](IplImage* p){ ::cvReleaseImage(\u0026p); } }; // this is ill-formed  \n```\nEvery lambda gets a unique type, so using a lambda as a deleter requires naming it to make it usable both as the class template argument (via `decltype()`) and as the constructor argument.  \nIt is currently not possible to use in-line unnamed lambdas as custom deleters.  \n\nThere is no class template argument deduction from a raw pointer type because it is impossible to distinguish a pointer obtained from array and non-array forms of new. This may be true in the general case, and may lead to undefined-behavior if the wrong default deleter is called (`delete` or `delete[]`) or when providing `operator[]` to a non-array pointer type. However, when the user is providing a custom deleter, this custom deleter will be called unconditionally regardless of any ambiguity in the default deleter case.    \n\nIt seems that **[unique.ptr.single.ctor]/16** is overly strict.\n\nThis use case is basically the whole point of having `unique_ptr` support deleters and the current wording makes the code cumbersome and error prone.\n\n## Proposal\n\n*Formal wording TBD*\n\nRelax the requirements of [unique.ptr.single.ctor]/16 to allow class template argument deduction in the case of a raw pointer and a user provided deleter.  \n\nAdd the following two deduction guides: \n```\ntemplate\u003ctypename T, typename D\u003e\nunique_ptr(T* p, D d)-\u003eunique_ptr\u003cT, D\u003e;\n\ntemplate\u003cclass T, class D\u003e \nunique_ptr(T, D)-\u003eunique_ptr\u003ctypename pointer_traits\u003ctypename D::pointer\u003e::element_type, D\u003e;\n```\n\nIn this case the raw pointer type `T*` shall default to a *non-array* pointer behavior and `operator[]` shall be *not* generated.\n\nFor raw _array pointers_, the user will *still* have to explicitly specify the template arguments as before if `operator[]` support is desired.\n\n\n## Discussion\n\nIn [P0433R1 §20.11 [smartptr]](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0433r1.html), the authors propose adding various deduction guides for `unique_ptr`, `shared_ptr` and `weak_ptr`. The proposed guides for `unique_ptr` also support the use case where a custom deleter is *not* specified. In that case the guide defaults to *non-array* raw pointers. As discussed above this might lead to undefined behaviour because the non-array version of `delete` will be applied to the array. This part of the propsal [was removed from newer revisions](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0433r2.html) of the proposal precisely for this reason. \n\u003e _The downside is that it will fail to deduce an array type ... We choose not to allow this problem, so we require that such deductions be ill-formed._  \n\nThe *current* proposal is limited only to the case where a custom deleter is supplied where UB is not possible. \n\nP0433R1 proposes a 3rd `unique_ptr` deduction guide:  \n`template\u003cclass U, class V\u003e unique_ptr(U, V) -\u003e unique_ptr\u003ctypename pointer_traits\u003cV::pointer\u003e::element_type, V\u003e;`  \nThis will not affect the case of using lambdas as deleters. Further examination of this guide is TBD before submission.\n\nFinally, note that the current proposal is not so pertinent to `shared_ptr\u003c\u003e` since the Deleter type is _not_ part of the `shared_ptr\u003c\u003e` type. \n\n\n#### Desirata\n\nIt would have been desirable if one could \"cast\" the raw pointer `T* p` to the *incomplete type* `T[]` such that the following would generate the array form of `unique_ptr\u003cT[],D\u003e` with `operator[]`:\n\n```\nunique_ptr up{ as_array(p), del };          // std::as_const() / std::move() form \nunique_ptr up{ array_cast\u003cint[]\u003e(p), del }; // alternative casting style form\nup[0] = 42;\n```\nAlas, as far as I understand, this is not currenty possible in the language and is beyond the scope of this proposal.\n\nA related \"ommision\" is `make_unique()` which does not currently have a form supporting custom deleters at all.    \nIf and when such a form will be added it would presumably support automatic type deduction. Such alternative `make_unique()` forms are also beyond the scope of this proposal.   \n\n\n## Acknowledgements\n\nI'd like to thank Agustín Bergé, Peter Dimov and Timur Doumler for very fruitful discussions and suggesting that this should be a proposal.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadishavit%2Fctad_for_unique_ptr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fadishavit%2Fctad_for_unique_ptr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fadishavit%2Fctad_for_unique_ptr/lists"}