120 lines
3.0 KiB
Plaintext
120 lines
3.0 KiB
Plaintext
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.
|
|
|
|
include::../../../shared_content/cfamily/trivially_copyable_types.adoc[]
|
|
|
|
== 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
|
|
|
|
[source,c,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
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
|
|
|
|
[source,c,diff-id=1,diff-type=compliant]
|
|
----
|
|
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
|
|
|
|
[source,cpp,diff-id=2,diff-type=noncompliant]
|
|
----
|
|
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
|
|
|
|
[source,cpp,diff-id=2,diff-type=compliant]
|
|
----
|
|
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
|
|
|
|
* {cpp} reference - https://en.cppreference.com/w/cpp/language/classes#Trivially_copyable_class[Definition of a trivially copyable class].
|
|
|
|
=== Related rules
|
|
|
|
* S4999 - "memcpy", "memmove", and "memset" should only be called with pointers to trivially copyable types
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Use "operator==" to check object equality, "XXX" is not a trivially copyable type without padding.
|
|
|
|
Compare member by member to check object equality, "XXX" contains padding.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 6 Nov 2018, 20:43:32 Ann Campbell wrote:
|
|
Double-check me [~loic.joly]
|
|
|
|
=== on 7 Nov 2018, 08:57:39 Loïc Joly wrote:
|
|
Looks good to me.
|
|
|
|
endif::env-github,rspecator-view[]
|