-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Smart Pointer Creation With Default Initialization #778
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
AdamBucior
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments about the product code changes.
| // FUNCTION TEMPLATE make_unique_for_overwrite | ||
| template <class _Ty, enable_if_t<!is_array_v<_Ty>, int> = 0> | ||
| _NODISCARD unique_ptr<_Ty> make_unique_for_overwrite() { // make a unique_ptr with default initialization | ||
| return unique_ptr<_Ty>(new _Ty); | ||
| } | ||
|
|
||
| template <class _Ty, enable_if_t<is_array_v<_Ty> && extent_v<_Ty> == 0, int> = 0> | ||
| _NODISCARD unique_ptr<_Ty> make_unique_for_overwrite(size_t _Size) { // make a unique_ptr with default initialization | ||
| using _Elem = remove_extent_t<_Ty>; | ||
| return unique_ptr<_Ty>(new _Elem[_Size]); | ||
| } | ||
|
|
||
| template <class _Ty, class... _Types, enable_if_t<extent_v<_Ty> != 0, int> = 0> | ||
| void make_unique_for_overwrite(_Types&&...) = delete; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be guarded with _HAS_CXX20.
| // Should this be in a separate ifdef _HAS_CXX20 control block since it is a | ||
| // different feature? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pretty sure it shouldn't.
| } | ||
| #endif // _HAS_CXX20 | ||
|
|
||
| // Once more, should this be in a separate #ifdef _HAS_CXX20 block? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same
|
|
||
| // CLASS TEMPLATE _Ref_count_obj2 | ||
| template <class _Ty> | ||
| template <class _Ty, _Init_form _Init> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't it be better to just introduce a new constructor taking some tag type? It's a polymorphic class so each instantiation needs to have it's own vtable. Ditto with all _Ref_count_*s.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree it would be better. Let me see what I can come up with.
| } | ||
|
|
||
| template <class _NoThrowIt> | ||
| template <class _NoThrowIt, _Init_form _Init> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, maybe just introduce a new member function. Something like _Push_back_for_overwrite.
miscco
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good from a short skimm, I would second @AdamBucior wrt the additional template arg
| template <class _Ty0> | ||
| friend enable_if_t<!is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared_for_overwrite(); | ||
|
|
||
| template <class _Ty0, class _Alloc> | ||
| friend enable_if_t<!is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> allocate_shared_for_overwrite( | ||
| const _Alloc& _Al_arg); | ||
|
|
||
| template <class _Ty0> | ||
| friend enable_if_t<is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared_for_overwrite(size_t _Count); | ||
|
|
||
| template <class _Ty0, class _Alloc> | ||
| friend enable_if_t<is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> allocate_shared_for_overwrite( | ||
| const _Alloc& _Al_arg, size_t _Count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is contrary to the "usual" way enable_if is used in the code. I would expect something along those lines:
| template <class _Ty0> | |
| friend enable_if_t<!is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared_for_overwrite(); | |
| template <class _Ty0, class _Alloc> | |
| friend enable_if_t<!is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> allocate_shared_for_overwrite( | |
| const _Alloc& _Al_arg); | |
| template <class _Ty0> | |
| friend enable_if_t<is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared_for_overwrite(size_t _Count); | |
| template <class _Ty0, class _Alloc> | |
| friend enable_if_t<is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> allocate_shared_for_overwrite( | |
| const _Alloc& _Al_arg, size_t _Count); | |
| template <class _Ty0, enable_if_t<!is_unbounded_array_v<_Ty0>, int> = 0> | |
| friend shared_ptr<_Ty0> make_shared_for_overwrite(); | |
| template <class _Ty0, class _Alloc, enable_if_t<!is_unbounded_array_v<_Ty0>, int> = 0> | |
| friend shared_ptr<_Ty0> allocate_shared_for_overwrite( | |
| const _Alloc& _Al_arg); | |
| template <class _Ty0, enable_if_t<is_unbounded_array_v<_Ty0>, int> = 0> | |
| friend shared_ptr<_Ty0> make_shared_for_overwrite(size_t _Count); | |
| template <class _Ty0, class _Alloc, enable_if_t<is_unbounded_array_v<_Ty0>, int> = 0> | |
| friend shared_ptr<_Ty0> allocate_shared_for_overwrite( | |
| const _Alloc& _Al_arg, size_t _Count); | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seemed a bit weird to me too, but I tried to copy the style used in make_shared.
EDIT: Here is an example.
template <class _Ty0, class... _Types>
friend enable_if_t<!is_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared(_Types&&... _Args);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was my doing in #309, where I took @AdamBucior's elegant concepts-based code and reimplemented it with neolithic stone tools SFINAE, because not all of our supported compilers have implemented concepts yet (e.g. IntelliSense). While we ordinarily use SFINAE in a highly consistent manner as @miscco noted, it doesn't work here 😿 due to the friendship (plus interaction with compiler bugs, IIRC). I think I was a bad kitty - instead of reducing and reporting the compiler bug, I perma-worked-around it (since default arg SFINAE would have needed verbose forward declarations anyways) by using paleolithic stone tools return type SFINAE.
(The issue with template argument SFINAE was whether friends can introduce default template arguments.)
I doubled down on my bad kitty behavior 😼 by jumping up on the table where I'm not allowed not marking this workaround as TRANSITION, because the SFINAE is ultimately doomed. In the future, when our C++20 compilers all support concepts, we can eradicate this and go back to Adam's original, elegant code.
| // different feature? | ||
| #if _HAS_CXX20 | ||
| template <class _Ty0> | ||
| friend enable_if_t<!is_unbounded_array_v<_Ty0>, shared_ptr<_Ty0>> make_shared_for_overwrite(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this use concepts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not all supported frontends support concepts. There is an issue #602 to change it later.
|
Maybe I'm missing something. If I change change the constructor to take an extra argument of type |
The best way would be to make one constructor take a tag type i.e. create a type like |
| tests\P0919R3_heterogeneous_unordered_lookup | ||
| tests\P0966R1_string_reserve_should_not_shrink | ||
| tests\P1023R0_constexpr_for_array_comparisons | ||
| tests\P1020R1_smart_pointer_for_overwrite |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should appear in sorted order.
| #define __cpp_lib_math_constants 201907L | ||
| #define __cpp_lib_remove_cvref 201711L | ||
| #define __cpp_lib_shift 201806L | ||
| #define __cpp_lib_smart_ptr_for_overwrite 201811L |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feature should also be mentioned in the list of _HAS_CXX20 features at the top of yvals_core.h.
| template <class _Ty, class _Alloc> | ||
| class _Ref_count_obj_alloc3 : public _Ebco_base<_Rebind_alloc_t<_Alloc, _Ty>>, public _Ref_count_base { | ||
| template <class _Ty, class _Alloc, _Init_form _Init> | ||
| class __declspec(empty_bases) _Ref_count_obj_alloc3 : public _Ebco_base<_Rebind_alloc_t<_Alloc, _Ty>>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We recently removed __declspec(empty_bases) from all control blocks, after noticing that it didn't actually have any effect (only _Ebco_base might be empty; _Ref_count_base never is), and it was causing compiler errors with CUDA 9.2. The 3 occurrences of __declspec(empty_bases) being added here should be removed again.
|
Is it still worked on? |
I think Gianni got busy after his internship ended and he hasn't had time to work on this. Someone will need to pickup the branch and finish it off - it hasn't quite managed to reach critical mass yet for one of the maintainers to do so. If someone else wants to copy Gianni's branch into their fork and finish this feature up, it would be amazing ;) |
I will work on this ;) |
|
Continuing this in #1315. |
|
Thanks again for starting this feature! |
Resolves #48. There are some comments throughout about minor wording/formatting doubts I have, otherwise I believe it should be complete.
stl/inc/memory: The reference count blocks got an additional non type template parameter of the newenumclass_Init_form, which specifies the initialization form.make_shared_for_overwriteandallocate_shared_for_overwrite, as well as helper functions for default-initing were implemented.stl/inc/xmemory:_Construct_in_place_for_overwrite, a helper function, was based on_Construct_in_place. The new one does default-init.tests/std/tests/P1020R1_smart_pointer_for_overwrite/test.cpp: Added test coverage formake_shared_for_overwriteandallocate_shared_for_overwrite.stl/inc/yvals_core.h: Added the feature test macro__cpp_lib_smart_ptr_for_overwritefor cxx20 mode.tests/std/tests/VSO_0157762_feature_test_macros/test.cpp: Added test coverage for__cpp_lib_smart_ptr_for_overwritein cxx20 mode.