Main Content

MISRA C++:2023 Rule 15.0.1

Special member functions shall be provided appropriately

Since R2024b

Description

Rule Definition

Special member functions shall be provided appropriately.

Rationale

Special member functions can be provided by the user or implicitly provided by the compiler. It is not always clear which user-declared special member function suppresses which implicitly provided special member function. This rule clarifies which special member functions need to be user-provided. The rule imposes these requirements:

  • Avoid declaring any of the special member functions, unless necessary. This requirement eliminates the need to needlessly mimicking the compiler provided special member functions.

  • Classes must fall into one of these categories: unmovable, move only, and copy enabled. This table summarizes the copyability and movability of these categories:

    CategoryMove ConstructibleMove AssignableCopy ConstructibleCopy Assignable
    UnmovableNoNoNoNo
    Move onlyYesOptionalNoNo
    Copy enabledYesOptionalYesOptional

    This requirement enforces that copy-constructible classes are also move constructible.

  • If a class has nondefault, user-provided or customized copy or move operations, it must also have customized destructor. A customized destructor is a destructor that contains at least one statement that is neither a compound statement nor a null statement. For example:

    struct myClass {
    	int i;
    	myClass(const myClass &other) {
    		i = other.i;
    	}
    
    	myClass(myClass &&other) {
    		i = other.i;
    	}
    
    	~myClass() { //Nondefault user provided destructor
    		i = 0;
    	}
    };
    This requirement enforces correct destruction of classes that handle resource.

  • If a move-only class has a customized destructor, it must also have customized move constructor. If the class is move assignable, it must also have customized move assignment operator. If a copy-enbabled class has a customized destructor, then it must also have customized copy constructor. If the class is copy-assignable, it must also have customized copy assignment operator. This requirement enforces correct copy and move operations for classes that handles resources.

  • If an unmovable class is used as a public base class, then the class must have a public virtual destructor. If a move-only or copy-enabled class is used as a public base class, it must have protected non-virtual destructor. This requirement reduces the risk of slicing. This requirement does not apply to aggregate classes.

Additionally, the rule requires that all out-of-class definitions of special member functions be placed in the same file.

Polyspace Implementation

Polyspace® reports a violation if one or more of these conditions are true:

  • A class does not match any of the copyability and movability combinations described in the preceding table. Such a class cannot be categorized as any of unmovable, move only, or copy enabled.

  • Assignment operators are partially defined.

  • A class is copy constructible but not move constructible.

  • A class is copy or move assignable but not constructible.

  • A class has a customized copy or move operation but no customized destructor.

  • A class has a customized destructor but lacks customized copy or move operations.

  • A nonaggregate unmovable public base class lacks a public virtual destructor.

  • A nonaggregate move-only or copy-enabled public base class lacks a protected non-virtual destructor.

  • An out-of-class definition of a special member function is placed in a different file than the other special member functions.

Troubleshooting

If you expect a rule violation but Polyspace does not report it, see Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

In this example, the class ResourceManager defines a customized move constructor but uses a default destructor. Polyspace reports a violation.

#include <iostream>

class ResourceManager {
private:
    int* data;

public:
    // Constructor
    explicit ResourceManager(int value) : data(new int(value)) {
        std::cout << "ResourceManager constructed with value: " << value << std::endl;
    }

    // Default Copy Constructor
    ResourceManager(const ResourceManager& other) = default;

    // Move Constructor
    ResourceManager(ResourceManager&& other) noexcept : data(other.data) {
        other.data = nullptr; // Nullify the source pointer
        std::cout << "ResourceManager moved" << std::endl;
    }

    // Default Destructor
    ~ResourceManager() = default;

    // Function to get the value
    int getValue() const {
        return data ? *data : 0; // Return 0 if data is nullptr
    }
};

Check Information

Group: Special member functions
Category: Required

Version History

Introduced in R2024b