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: 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, good
struct base {
virtual void update() = 0;
std::shared_ptr<int> sp;
};
struct derived : public base {
void update() override {}
};
Example, bad
void init(derived& a)
{
memset(&a, 0, sizeof(derived));
}
This is type-unsafe and overwrites the vtable.
Example, bad
void copy(derived& a, derived& b)
{
memcpy(&a, &b, sizeof(derived));
}
This is also type-unsafe and overwrites the vtable.
Enforcement
- Flag passing a non-trivially-copyable type to
memsetormemcpy.
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. A resource handle is a class that owns a resource; std::vector is the typical resource handle; its resource is its sequence of elements.
Summary of container rules:
- C.100: Follow the STL when defining a container
- C.101: Give a container value semantics
- C.102: Give a container move operations
- C.103: Give a container an initializer list constructor
- C.104: Give a container a default constructor that sets it to empty
- ???
- C.109: If a resource handle has pointer semantics, provide
*and->
See also: Resources