Rule M18-2-1 (required, implementation, automated)
The macro offsetof shall not be used. See MISRA C++ 2008 [7]
The dynamic memory management provides flexible mechanism of allocating and deallocating blocks of memory during run-time phase of the program. The application is allowed to acquire as much memory as it needs in its current state, and return it once the memory is not used.
Moreover, this is a convenient way of extending lifetime of objects outside the functions where the objects were created. In other words, a function can create objects on dynamic memory and then exit and the objects that were created in the dynamic memory are preserved and can be used subsequently by other functions. The dynamic memory management uses the Operating System routines to allocate and deallocate memory, what introduces several issues. Therefore, the AUTOSAR C++14 Coding Guidelines defines specific rules for appropriate usage and implementation of dynamic memory management. Challenges arising due to dynamic memory usage Issue:
Solution:
Memory leaks
RAII design pattern usage is highly recommended for managing resource and memory acquisition and release (A18-5-2). It is prohibited to make calls to new and delete operators explicitly, to force programmers to assign each allocated memory block to manager object which deallocates the memory automatically on leaving its scope. Also, the form of delete operator used for memory deallocation needs to match the form of new operator used for memory allocation (A18-5-3).
Memory fragmentation
Memory allocator used in the project needs to guarantee that no memory fragmentation occurs (A18-5-5).
Invalid memory access
C-style functions malloc/calloc/realloc must not be used in the project, so memory block can not be accessed as it would be of another type. Memory allocator used in the project needs to guarantee that objects do not overlap in the physical storage (A185-5).
Erroneous memory allocations
The application program needs to define the maximum amount of dynamic memory it needs, so running out of memory must not occur during faultless execution. The memory would be preallocated before run-time phase of the program (A18-5-5).
Not deterministic execution time of memory allocation and deallocation
Memory allocator used in the project needs to guarantee that memory allocation and deallocation are executed within defined time constraints that are appropriate for the response time constraints defined for the real-time system and its programs (A18-5-7).
Table 6.2: Challenged of dynamic memory usage
Ownership and smart pointers Memory allocated dynamically requires strict control of objects or functions that are responsible for deallocating it when it is no longer needed. Such lifetime manipulation and maintenance of managing dynamically allocated memory is called Ownership. Ownership has the following features: if it is exclusive, then it is possible to transfer it from one scope to another. if it is shared, then memory deletion is typically responsibility of the last owner that releases that ownership. if it is temporary, then a non-owning/weak reference has to be converted to shared ownership before accessing the object. Since C++11, management of Ownership is done by smart pointer types. Smart pointers are allocated on stack, which guarantees destructor execution and possible object deallocation (if that is the last or sole owner) at the end of the scope. Pointerlike behavior is done by overloading operator-> and operator* methods. The following standard smart pointer classes are available since C++11: std::unique_ptr wraps a pointer to an object in an exclusive way. Such std:: unique_ptr
object guarantees that only one pointer to the underlying object exists at a time, as std::unique_ptr is not copyable. It is movable and such an operation represents ownership transfer. When the std::unique_ptr instance is goes out of scope, the underlying pointer is deleted and memory is deallocated. std::shared_ptr wraps a pointer to an object in a shared way. Multiple std:: shared_ptr
are capable to point at the same object, as std::shared_ptr is copyable and it contains a reference counting mechanism. When the last std::shared_ptr instance goes out of scope (and the reference counter drops to 0), the underlying pointer is deleted and memory is deallocated. std::weak_ptr wraps a pointer to an object, but it has to be converted to a std ::shared_ptr in order to access the referenced object. The main purpose of the std::weak_ptr is to break potential circular references among multiple std ::shared_ptr
objects, which would prevent reference counting from dropping to 0 and removing the underlying pointer. If only std::weak_ptr objects exist at a time, then conversion to std::shared_ptr will return an empty std::shared_ptr.
The main purpose of smart pointers is prevent from possible memory leaks to provide limited garbage-collection feature: with almost no overhead over raw pointers for std::unique_ptr, unless userspecified deleter is used. with possibility of sharing ownership among multiple std::shared_ptr objects. However, this solution bases purely on the reference-counting and smart pointers destructors calling and it does not involve independent process that periodically cleans up memory that is no longer referenced.
Usage of smart pointers makes Ownership matters unambiguous and selfdocumenting. It also facilitates memory management issues and eliminates multiple error types that can be made by developers. There are also other types of memory managing objects that follow RAII design pattern, e.g. std::string and std::vector.