SonarSource Rules
  • Products

    In-IDE

    Code Quality and Security in your IDE with SonarQube Ide

    IDE extension that lets you fix coding issues before they exist!

    Discover SonarQube for IDE

    SaaS

    Code Quality and Security in the cloud with SonarQube Cloud

    Setup is effortless and analysis is automatic for most languages

    Discover SonarQube Cloud

    Self-Hosted

    Code Quality and Security Self-Hosted with SonarQube Server

    Fast, accurate analysis; enterprise scalability

    Discover SonarQube Server
  • SecretsSecrets
  • ABAPABAP
  • AnsibleAnsible
  • ApexApex
  • AzureResourceManagerAzureResourceManager
  • CC
  • C#C#
  • C++C++
  • CloudFormationCloudFormation
  • COBOLCOBOL
  • CSSCSS
  • DartDart
  • DockerDocker
  • FlexFlex
  • GitHub ActionsGitHub Actions
  • GoGo
  • HTMLHTML
  • JavaJava
  • JavaScriptJavaScript
  • JSONJSON
  • JCLJCL
  • KotlinKotlin
  • KubernetesKubernetes
  • Objective CObjective C
  • PHPPHP
  • PL/IPL/I
  • PL/SQLPL/SQL
  • PythonPython
  • RPGRPG
  • RubyRuby
  • RustRust
  • ScalaScala
  • ShellShell
  • SwiftSwift
  • TerraformTerraform
  • TextText
  • TypeScriptTypeScript
  • T-SQLT-SQL
  • VB.NETVB.NET
  • VB6VB6
  • XMLXML
  • YAMLYAML
C++

C++ static code analysis

Unique rules to find Bugs, Vulnerabilities, Security Hotspots, and Code Smells in your C++ code

  • All rules 798
  • Vulnerability14
  • Bug173
  • Security Hotspot19
  • Code Smell592

  • Quick Fix 99
Filtered: 4 rules found
misra-directive
    Impact
      Clean code attribute
        1. A function call shall not violate the function's preconditions

           Bug
        2. Floating-point arithmetic should be used appropriately

           Bug
        3. "User-provided" "copy assignment operators" and "move assignment operators" shall handle self-assignment

           Code Smell
        4. Sections of code should not be "commented out"

           Code Smell

        "User-provided" "copy assignment operators" and "move assignment operators" shall handle self-assignment

        intentionality - complete
        maintainability
        reliability
        Code Smell
        • pitfall
        • misra-c++2023
        • misra-required
        • misra-directive

        Why is this an issue?

        More Info

        This rule is part of MISRA C++:2023.

        Usage of this content is governed by Sonar’s terms and conditions. Redistribution is prohibited.

        Dir 15.8.1 - User-provided copy assignment operators and move assignment operators shall handle self-assignment

        [swappable.requirements]
        [moveassignable]
        [copyassignable]

        Category: Required

        Amplification

        Types supporting copy assignment shall satisfy the CopyAssignable requirement.

        Types supporting move assignment shall satisfy the MoveAssignable requirement.

        Additionally, in the case of self-assignment, user-provided copy assignment operators and move assignment operators shall:

        • Not have undefined behaviour; and
        • Not leak any resources; and
        • Preserve the value of the self-assigned object.

        Note: what constitutes the value of an object depends on a class’s design, and is usually related to the semantics of the equality operator.

        Rationale

        Class designs that require user-provided copy assignment operators or move assignment operators can be avoided when it is possible to use a manager class [1] (see M23_372: MISRA C++ 2023 Rule 15.0.1), such as smart pointers and the containers provided by the C++ Standard Library. However, when implementing a manager class [1], care needs to be taken when defining user-provided copy assignment operators and move assignment operators.

        Naïve implementations, particularly in the presence of self-assignment, can lead to undefined behaviour, resource leaks, performance issues and unintended violations of the object’s semantics. Self-assignment is rarely intentional, but it is often hard to spot when it occurs — for example, when manipulating overlapping ranges of objects.

        This directive extends the CopyAssignable and MoveAssignable requirements to all types supporting these assignments, and additionally requires that the state of the object is preserved after a self-assignment. This is done to ensure that the behaviour is predictable and that no resources are leaked.

        Well-known idioms, such as copy-and-swap, may help when complying with this directive. However, as there is no one-solution-fits-all, this directive does not recommend a specific idiom.

        Example

        The following is a simplified implementation of a container, similar to std::vector. The class implements a general manager [2], and so user-provided copy assignment operators and move assignment operators are required.

        class Vector
        {
          std::size_t   size_;
          int32_t     * buffer_;
        
        public:
          Vector() : size_( 0 ), buffer_( nullptr ) {}
          Vector( std::size_t size ) : size_( size ), buffer_( new int[ size ] ) {}
        
          ~Vector()
          {
            delete[] this->buffer_;
          }
        
          Vector( Vector const & other ) :
            size_( other.size_ ),
            buffer_( other.size_ != 0 ? new int32_t[ other.size_ ] : nullptr )
          {
            ( void )std::copy_n( other.buffer_, size_, this->buffer_ );
          }
        
          Vector( Vector  && other ) noexcept :
            size_( std::exchange( other.size_, 0 ) ),
            buffer_( std::exchange( other.buffer_, nullptr ) )
          {}
        
          Vector & operator=( Vector const & other ) &;
          Vector & operator=( Vector && other ) & noexcept;
        };
        

        Heading: Copy assignment

        The following implementation of copy assignment is non-compliant due to the presence of undefined behaviour for self-assignment.

        Vector & Vector::operator=( Vector const & other ) &
        {
          this->size_ = other.size_;
          delete[] this->buffer_;                  // Deletes other.buffer_
          this->buffer_ = new int[ other.size_ ];  // Reading from deleted storage,
                                                   //   resulting in undefined behaviour
          ( void )std::copy_n( other.buffer_,
                               other.size_,
                               this->buffer_ );
          return *this;
        }
        

        This undefined behaviour can be prevented by introducing a check for self-assignment.

        Vector & Vector::operator=( Vector const & other ) &
        {
          if ( this != std::addressof( other ) )
          {
            this->size_ = other.size_;
            delete[] this->buffer_;
            this->buffer_ = new int[ other.size_ ];
        
            ( void )std::copy_n( other.buffer_,
                                 other.size_,
                                 this->buffer_ );
          }
        
          return *this;
        }
        

        The check for self-assignment is a valid solution in this case, but it does not guarantee a correct implementation in all cases (e.g., self-referential data structures). It also has several disadvantages which are outside of the scope of this directive, but which may need to be considered in the final design:

        • Pessimization of performance for the (presumably) rare case of self-assignment; and
        • Code duplication within the destructor (deletion of elements and the buffer) and the copy constructor (deep copy of elements); and
        • Failure to provide the strong exception safety guarantee.

        These concerns are addressed when using the copy-and-swap idiom.

        Vector & Vector::operator=( Vector const & other ) &
        {
          Vector tmp( other );                      // Copy construction, with deep copying
          std::swap( this->size_,   tmp.size_   );
          std::swap( this->buffer_, tmp.buffer_ );
        
          return *this;
        
          // tmp goes out of scope and thus takes care of deleting the previous buffer
        }
        

        Self-assignment is handled appropriately when using the copy-and-swap idiom. However, the creation of a new buffer invalidates any iterators or references to elements of the original Vector, and it requires unnecessary duplication of resources. Whilst not shown in the above, these issues can be avoided by introducing a check for self-assignment around the copy-and-swap algorithm.

        Heading: Move assignment

        The following implementation of move assignment has no undefined behaviour, but the Vector will be released when self-assignment takes place. By any reasonable notion of equivalence, the value is not preserved.

        Vector & Vector::operator=( Vector && other ) & noexcept
        {
          delete[] this->buffer_;
          this->size_   = std::exchange( other.size_,   0       );
          this->buffer_ = std::exchange( other.buffer_, nullptr );
        
          return *this;
        }
        

        The following example addresses these issues by using the move-and-swap idiom.

        Vector & Vector::operator=( Vector && other ) & noexcept
        {
            Vector tmp( std::move( other ) );
        
            std::swap( this->size_,   tmp.size_   );
            std::swap( this->buffer_, tmp.buffer_ );
        
            return *this;
        }
        

        When self-assignment takes place, the call to std::move transfers ownership of the resources to the temporary object tmp, and then the calls to std:swap returns their ownership back to *this. There are no changes to the state of *this and duplication of resources does not occur. Whilst not shown, a check for self-assignment may be included to avoid unnecessary operations.

        Glossary

        [1] Manager class

        A class that is either a scoped manager [3], a unique manager [4], or a general manager [2] as defined in M23_372: MISRA C++ 2023 Rule 15.0.1.

        [2] General manager

        A manager class [1], as defined in M23_372: MISRA C++ 2023 Rule 15.0.1.

        [3] Scoped manager

        A manager class [1], as defined in M23_372: MISRA C++ 2023 Rule 15.0.1.

        [4] Unique manager

        A manager class [1], as defined in M23_372: MISRA C++ 2023 Rule 15.0.1.

        Copyright The MISRA Consortium Limited © 2023

          Available In:
        • SonarQube IdeCatch issues on the fly,
          in your IDE
        • SonarQube CloudDetect issues in your GitHub, Azure DevOps Services, Bitbucket Cloud, GitLab repositories
        • SonarQube ServerAnalyze code in your
          on-premise CI

        © 2025 SonarSource Sàrl. All rights reserved.

        Privacy Policy | Cookie Policy | Terms of Use