149 lines
3.7 KiB
Plaintext
149 lines
3.7 KiB
Plaintext
This rule raises an issue if a division of `sizeof` is used to compute the size of an array,
|
|
that could be replaced with `std::size` or `std::ranges::size` (since {cpp}20).
|
|
|
|
== Why is this an issue?
|
|
|
|
C-arrays do not expose their number of elements as a data member or a member function.
|
|
This information is present in the type system.
|
|
|
|
In {cpp} it can be extracted by calling `std::size` (introduced in {cpp}17) or `std::ranges::size` (introduced in {cpp}20),
|
|
as these functions support C-arrays in addition to containers and ranges.
|
|
|
|
The historical way, inherited from C, is to divide the size of the array by the size of the element type.
|
|
However, using this solution does not convey the intent of the code as clearly,
|
|
and is prone to producing incorrect values when:
|
|
|
|
* the element type is changed but the `sizeof` code was not updated,
|
|
* `sizeof` was applied to pointer produced from array decay instead of the array itself.
|
|
|
|
This rule raises an issue when the division of `sizeof` is used to compute the number of elements in an array.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
int carr[10];
|
|
|
|
void process() {
|
|
std::size_t size = sizeof(carr) / sizeof(int); // Noncompliant
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=1,diff-type=compliant]
|
|
----
|
|
int carr[10];
|
|
|
|
void process() {
|
|
std::size_t size = std::size(carr); // Compliant
|
|
}
|
|
----
|
|
|
|
The rule also detects cases where the `sizeof` division is expanded from a macro:
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof((arr)[0])
|
|
|
|
int carr[10];
|
|
|
|
void process() {
|
|
std::size_t size = ARRAY_SIZE(carr); // Noncompliant
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=2,diff-type=compliant]
|
|
----
|
|
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof((arr)[0])
|
|
|
|
int carr[10];
|
|
|
|
void process() {
|
|
std::size_t size = std::size(carr); // Compliant
|
|
}
|
|
----
|
|
|
|
Once all uses of the `ARRAY_SIZE` macro have been removed, the macro should also be removed.
|
|
However doing so is not required to address the issues raised by this rule,
|
|
as this allows code the be fixed incrementally.
|
|
|
|
=== `std::array` is also covered
|
|
|
|
This rule will also raise an issue when the `sizeof` division,
|
|
is used to compute the size of the `std::array` type.
|
|
|
|
Such code may be leftover from the replacement of C-array,
|
|
without updating all necessary call sites (see S5954).
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=3,diff-type=noncompliant]
|
|
----
|
|
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof((arr)[0])
|
|
|
|
std::array<int, 10> arr;
|
|
|
|
void process() {
|
|
std::size_t size1 = sizeof(arr) / sizeof(int); // Noncompliant
|
|
std::size_t size2 = ARRAY_SIZE(arr); // Noncompliant
|
|
}
|
|
----
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=3,diff-type=compliant]
|
|
----
|
|
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof((arr)[0])
|
|
|
|
std::array<int, 10> arr;
|
|
|
|
void process() {
|
|
std::size_t size1 = std::size(arr); // Compliant
|
|
std::size_t size2 = std::size(arr); // Compliant
|
|
}
|
|
----
|
|
|
|
Alternatively, the `size` member function may be invoked in a non-generic code.
|
|
|
|
[source,cpp]
|
|
----
|
|
#define ARRAY_SIZE(arr) sizeof(arr) / sizeof((arr)[0])
|
|
|
|
std::array<int, 10> arr;
|
|
|
|
void process() {
|
|
std::size_t size1 = arr.size(); // Compliant
|
|
std::size_t size2 = arr.size(); // Compliant
|
|
}
|
|
----
|
|
|
|
=== How does this work?
|
|
|
|
The implementation of `std::size` for arrays relies on template argument deduction
|
|
to deduce the size of the array from the parameter that references an array type:
|
|
|
|
[source,cpp]
|
|
----
|
|
template<typename T, std::size_t N>
|
|
constexpr N my_size(T const& (arr)[N]) {
|
|
return N;
|
|
}
|
|
|
|
int arr[10];
|
|
std::size_t s = my_size(arr); // Deduces: "N" == 10
|
|
----
|
|
|
|
== Resources
|
|
|
|
=== Related rules
|
|
|
|
* S5945 - suggest replacing C-arrays with `std::array` and `std::vector`
|
|
|