Main Content

MISRA C++:2023 Rule 15.0.2

User-provided copy and move member functions of a class should have appropriate signatures

Since R2024b

Description

Rule Definition

User-provided copy and move member functions of a class should have appropriate signatures.

Rationale

This table lists the suggested signatures of user-provided copy and move member functions for a class X, along with an explanation of each function signature.

Function SignatureExplanation

Copy constructor

X( X const &)

The copy constructor takes a const reference parameter (X const &) and creates a copy of an existing object or passes an object by value to a function.

The const qualifier prevents the source object from being modified, which is typically the developer intent.

Move constructor

X( X && ) noexcept

The move constructor takes an rvalue reference to another instance (X &&) and moves the resources of that instance to a new object. The move operation leaves the moved-from object in a valid but unspecified state.

The constructor is declared as noexcept to indicate that the move operation does not throw, which prevents the source object from ending up in an unexpected partially moved-from state.

Copy assignment operator

X & operator=( X const & ) &

The copy assignment operator takes a const reference parameter (X const &) and copies the contents of an object to another existing object.

The function returns an lvalue reference to the current object (X &), which allows the chaining of assignment operations.

The reference qualifier after the parentheses (&) indicates that the operator can be called only on lvalue X objects, which prevents assignments to temporary rvalue objects.

Move assignment operator

X & operator=( X && ) & noexcept

The move assignment operator takes an rvalue reference to another instance (X &&) and moves the resources of that instance to another existing object. The move operation leaves the moved-from object in a valid but unspecified state.

The function returns an lvalue reference to the current object (X &), which allows the chaining of assignment operations.

The reference qualifier after the parentheses (&) indicates that the operator can be called only on lvalue X objects, which prevents assignments to temporary rvalue objects.

The assignment operator is declared as noexcept to indicate that the move operation does not throw, which prevents the source object from ending up in an unexpected partially moved-from state.

The coding rule allows the addition of these keywords to the signatures of user-provided copy and move member functions:

  • constexpr — Add to the signature any of the constructors or assignment operators.

  • explicit — Add to the signature of the copy or move constructors.

  • noexcept — Add to the signature of the copy operations. The noexcept can be conditional.

If you do not intend to use the result of an assignment operation, you can declare copy and move assignment operators with a return type of void.

Polyspace Implementation

The coding rule checker reports a violation if there is a mismatch between the actual and expected signatures of user-provided move and copy member functions. If there is more than one mismatch, Polyspace reports only one violation but shows one message per mismatch. For example, if the signature of a copy assignment operator uses the wrong return type and is missing the const qualifier, Polyspace reports one violation with two messages.

If you declare a noncompliant move or copy function and then define it elsewhere, Polyspace® reports the violation for the declaration.

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

#include <algorithm> 
#include <iostream>

class CustomClass
{

public:
    // Constructor
    CustomClass() {}
    // Destructor
    ~CustomClass() {
        std::cout << "Destructor called\n";
    }

    // Copy Constructor
    CustomClass(CustomClass &other)                  // Noncompliant
    {
        // Create copy of other
    }

    // Move Constructor
    CustomClass(CustomClass &&other)                 // Noncompliant
    {
        // Move from other to new object
    }

    // Copy Assignment Operator
    CustomClass &operator=(const CustomClass &other) // Noncompliant
    {
        if (this != &other)
        {
            // Copy from other to another existing object
        }
        return *this;
    }

    // Move Assignment Operator
    CustomClass &operator=(CustomClass &&other)      // Noncompliant
    {
        if (this != &other)
        {
            // Perform move from other to another existing object
        }
        return *this;
    }
};

In this example, Polyspace reports a violation for each CustomClass move or copy constructor as well as for the assignment operators:

  • The signature of the copy constructor is missing a const qualifier, which can result in the modification of the source object.

  • The signature of the move constructor is missing a noexcept keyword. If the move operation throws, the moved-from object can end up in an invalid state.

  • The signature of the copy assignment operator is missing an lvalue reference qualifier (&) after the parentheses, which can result in an assignment to a temporary object.

  • The signature of the move assignment operator is missing a noexcept and an lvalue reference qualifier (&) after the parentheses. The risks associated with this noncompliant signature are the same as those for the move constructor and the copy assignment operator.

    Note that Polyspace reports the missing noexcept keyword and lvalue reference qualifier as a single violation.

    This code shows the copy and move member functions with appropriate signatures:

    #include <algorithm> 
    #include <iostream>
    
    class CustomClass
    {
    
    public:
        // Constructor
        CustomClass() {}
        // Destructor
        ~CustomClass() {
            std::cout << "Destructor called\n";
        }
    
        // Copy Constructor
        CustomClass(CustomClass const &other)                  // Compliant
        {
            // Create copy of other
        }
    
        // Move Constructor
        CustomClass(CustomClass &&other)  noexcept               // Compliant
        {
            // Move from other to new object
        }
    
        // Copy Assignment Operator
        CustomClass &operator=(const CustomClass &other)& // Compliant
        {
            if (this != &other)
            {
                // Copy from other to another existing object
            }
            return *this;
        }
    
        // Move Assignment Operator
        CustomClass &operator=(CustomClass &&other)& noexcept     // Compliant
        {
            if (this != &other)
            {
                // Perform move from other to another existing object
            }
            return *this;
        }
    };

Check Information

Group: Special member functions
Category: Advisory

Version History

Introduced in R2024b