diff --git a/CppCoreGuidelines.md b/CppCoreGuidelines.md index b5c2349..5e54a54 100644 --- a/CppCoreGuidelines.md +++ b/CppCoreGuidelines.md @@ -4512,6 +4512,7 @@ Other default operations rules: * [C.86: Make `==` symmetric with respect of operand types and `noexcept`](#Rc-eq) * [C.87: Beware of `==` on base classes](#Rc-eq-base) * [C.89: Make a `hash` `noexcept`](#Rc-hash) +* [C.90: Rely on constructors and assignment operators, not memset and memcpy](#Rc-memset) ## C.defop: Default Operations @@ -6539,6 +6540,37 @@ That tends to work better than "cleverness" for non-specialists. * Flag throwing `hash`es. +### C.90: Rely on constructors and assignment operators, not `memset` and `memcpy` + +##### Reason + +The standard C++ mechanism to construct an instance of a type is to call its constructor. As specified in guideline [C.41](#Rc-complete): a constructor should create a fully initialized object. No additional initialization, such as by `memcpy`, should be required. +A type will provide a copy constructor and/or copy assignment operator to appropriately make a copy of the class, preserving the type's invariants. Using memcpy to copy a non-trivially copyable type has undefined behavior. Frequently this results in slicing, or data corruption. + +##### Example, bad + + struct base + { + virtual void update() = 0; + std::shared_ptr sp; + }; + + struct derived : public base + { + void update() override {} + }; + + void init(derived& a) + { + memset(&a, 0, sizeof(derived)); + } + + void copy(derived& a, derived& b) + { + memcpy(&a, &b, sizeof(derived)); + } + + ## C.con: Containers and other resource handles A container is an object holding a sequence of objects of some type; `std::vector` is the archetypical container. @@ -18904,7 +18936,7 @@ Doing so takes away an `#include`r's ability to effectively disambiguate and to ##### Note An exception is `using namespace std::literals;`. This is necessary to use string literals -in header files and given [the rules](http://eel.is/c++draft/over.literal) - users are required +in header files and given [the rules](http://eel.is/c++draft/over.literal) - users are required to name their own UDLs `operator""_x` - they will not collide with the standard library. ##### Enforcement @@ -20087,12 +20119,12 @@ and errors (when we didn't deal correctly with semi-constructed objects consiste my = y; data = nullptr; } - + ~Picture() { Cleanup(); } - + bool Init() { // invariant checks @@ -20105,14 +20137,14 @@ and errors (when we didn't deal correctly with semi-constructed objects consiste data = (char*) malloc(mx*my*sizeof(int)); return data != nullptr; } - + void Cleanup() { if (data) free(data); data = nullptr; } }; - + Picture picture(100, 0); // not ready-to-use picture here // this will fail.. if (!picture.Init()) { @@ -20127,14 +20159,14 @@ and errors (when we didn't deal correctly with semi-constructed objects consiste size_t mx; size_t my; vector data; - + static size_t check_size(size_t s) { // invariant check Expects(s > 0); return s; } - + public: // even more better would be a class for a 2D Size as one single parameter Picture(size_t x, size_t y) @@ -20147,10 +20179,10 @@ and errors (when we didn't deal correctly with semi-constructed objects consiste } // compiler generated dtor does the job. (also see C.21) }; - + Picture picture1(100, 100); // picture is ready-to-use here... - + // not a valid size for y, // default contract violation behavior will call std::terminate then Picture picture2(100, 0); diff --git a/scripts/hunspell/isocpp.dic b/scripts/hunspell/isocpp.dic index f5a9c18..80b7d54 100644 --- a/scripts/hunspell/isocpp.dic +++ b/scripts/hunspell/isocpp.dic @@ -301,6 +301,7 @@ md memberinit members' memcmp +memcpy memmove memoization memoized