
Co-authored-by: Marco Borgeaud <89914223+marco-antognini-sonarsource@users.noreply.github.com>
45 lines
2.5 KiB
Plaintext
45 lines
2.5 KiB
Plaintext
== Why is this an issue?
|
|
|
|
For the integration with the C or just older APIs, it may be useful to convert a contiguous iterator to a raw pointer to the element.
|
|
In {cpp}20 ``++std::to_address++`` was introduced to perform this operation on both iterators and smart pointers, which supersedes non-portable and potentially buggy workarounds, that were required before:
|
|
|
|
* The first option was to take the address of the element pointed by the iterator: ``++&*it++``. However, this operation has undefined behavior if the iterator is not pointing to any element. This may happen for the iterator returned by a call to ``++end()++`` on the container. This may also be the case when we need the address to construct a new object (via placement new) at the location pointed to by the iterator. ``++std::to_address(it)++`` works in such cases.
|
|
* The second option was to exploit the nature of ``++operator->++`` overloading and call it explicitly on the iterator: ``++it.operator->()++``. This option avoids the pitfalls of the previous one, at the cost of not being portable. It would fail on the implementations that use raw-pointers as iterators for contiguous ranges like ``++std::vector++`` or ``++std::span++``. Moreover, it is confusing, as this functional notation syntax for operators is rarely used.
|
|
|
|
While both ``++std::to_address++`` and above workarounds, can be always used to get the address of the element that the iterator is pointing to (if any), incrementing or decrementing may have undefined behavior.
|
|
Performing pointer arithmetic on pointer to elements is safe only in the case of contiguous iterators (e.g. iterators of `std::vector`, `std::array`, `std::span`, `std::string` or `std::string_view`).
|
|
|
|
This rule raises an issue when dereferencing a pointer-like object is immediately followed by taking the address of the result (``++&*x++`` or ``++std::addressof(*x)++``) or when ``++operator->++`` is called through an explicit functional notation (``++x.operator->()++``).
|
|
|
|
|
|
=== Noncompliant code example
|
|
|
|
[source,cpp]
|
|
----
|
|
void check(int* b, int* e);
|
|
|
|
void func1(std::vector<int>& v) {
|
|
check(v.begin().operator->(), v.end().operator->()); // Noncompliant
|
|
}
|
|
|
|
void func2(span<int> s) {
|
|
check(&*s.begin(), &*s.end()); // Noncompliant
|
|
}
|
|
|
|
----
|
|
|
|
|
|
=== Compliant solution
|
|
|
|
[source,cpp]
|
|
----
|
|
void func1(std::vector<int>& v) {
|
|
check(std::to_address(v.begin()), std::to_address(v.end()));
|
|
}
|
|
|
|
void func2(span<int> s) {
|
|
check(std::to_address(s.begin()), std::to_address(s.end()));
|
|
}
|
|
----
|
|
|