-
Notifications
You must be signed in to change notification settings - Fork 9.1k
Fix small_vector issues when assigning it to itself #15525
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
Fix small_vector issues when assigning it to itself #15525
Conversation
| size_t _capacity; | ||
| size_t _size; |
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.
By not initializing these fields, the move constructor avoids writing to these members twice.
| reserve(other._size); | ||
|
|
||
| std::uninitialized_copy(other.begin(), other.end(), _uninitialized_begin()); | ||
| _size = other._size; |
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.
These 3 lines are now moved 1:1 into _copy_assign. This allows us to call _copy_assign without a prior clear in the constructor, because a newly constructed vector can't possibly have anything that needs to be cleared.
This makes the diff large, but actually barely anything changed.
| if (other._capacity == N) | ||
| { | ||
| _data = &_buffer[0]; | ||
| _capacity = N; | ||
| _size = other._size; | ||
| // The earlier static_assert(std::is_nothrow_move_constructible_v<T>) | ||
| // ensures that we don't exit in a weird state with invalid `_size`. | ||
| #pragma warning(suppress : 26447) // The function is declared 'noexcept' but calls function '...' which may throw exceptions (f.6). | ||
| std::uninitialized_move(other.begin(), other.end(), _uninitialized_begin()); | ||
| std::destroy(other.begin(), other.end()); | ||
| } | ||
| else | ||
| { | ||
| _data = other._data; | ||
| _capacity = other._capacity; | ||
| _size = other._size; | ||
| _move_assign(other); | ||
| } | ||
|
|
||
| other._data = &other._buffer[0]; | ||
| other._capacity = N; | ||
| other._size = 0; |
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.
These 21 lines are moved 1:1 into _move_assign, for the same reason as for _copy_assign.
carlos-zamora
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.
Pretty straightforward. Thanks for writing some comments in the PR! Made it much easier to review!
This commit achieves fixes the issue as described in the title by
checking whether the
thisandotherpointer are identical.As an added bonus it makes the copy and move constructors slightly
cheaper, as they don't try to destruct existing data anymore,
which doesn't exist anyways.
Validation Steps Performed