The function memcmp
only returns meaningful results for objects of trivially copyable types without padding. This includes scalar
types, arrays, and trivially copyable classes.
Why is this an issue?
memcmp
compares the raw memory representation of two objects (what the standard calls their object representation). When
objects are not trivially copyable or contain padding, they could have different raw memory representations even though they store identical values.
So the result of memcmp
is not meaningful.
Padding refers to the insertion of additional bits into a structure or class to ensure proper alignment of its members in memory.
Trivially copyable types include:
- scalar types
- trivially copyable classes
- arrays of these types
A class is trivially copyable when:
- all its non-static data members and base classes are trivially copyable types,
- it has no virtual functions or base classes,
- its destructor is trival,
- and one or more of the following special member functions is trivial, and the rest are deleted: copy constructor, move constructor, copy
assignment operator, and move assignment operator.
Note: a default implementation is always considered trivial, both when it is explicit (with = default
) or implicit (if the special
member function is omitted).
How to fix it
The comparison operator operator==
should be defined and used instead of memcmp
when the types are not trivially copyable
or contain padding. This allows comparing member by member to check object equality.
Code examples
Noncompliant code example
struct Shape { // Trivially copyable, but will contain padding after the bool on most architectures
bool visible;
int x;
int y;
};
bool isSame(Shape *s1, Shape *s2)
{
return memcmp(s1, s2, sizeof(Shape)) == 0; // Noncompliant
}
Compliant solution
struct Shape { // Trivially copyable, but will contain padding after the bool on most architectures
bool visible;
int x;
int y;
};
bool isSame(Shape *s1, Shape *s2)
{
return s1->visible == s2->visible && s1->x == s2->x && s1->y == s2->y;
}
Noncompliant code example
class Resource { // Not trivially copyable
public:
Ptr* ptr;
~Resource();
};
bool isSame(Resource *r1, Resource *r2)
{
return memcmp(r1, r2, sizeof(Resource)) == 0; // Noncompliant
}
Compliant solution
class Resource { // Not trivially copyable
public:
Ptr* ptr;
~Resource();
};
bool operator==(Resource const &r1, Resource const &r2) {
return r1.ptr == r2.ptr;
}
bool isSame(Resource *r1, Resource *r2)
{
return (*r1) == (*r2);
}
Resources
Documentation
Related rules
- S4999 - "memcpy", "memmove", and "memset" should only be called with pointers to trivially copyable types