rspec/rules/S6225/cfamily/rule.adoc
Fred Tingaud d3cfe19d7e
Fix broken or dangerous backquotes
Co-authored-by: Marco Borgeaud <89914223+marco-antognini-sonarsource@users.noreply.github.com>
2023-10-30 10:33:56 +01:00

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()));
}
----