Main Content

MISRA C++:2023 Rule 6.2.3

The source code used to implement an entity shall appear only once

Since R2024b

Description

The source code used to implement an entity shall appear only once 1

Rationale

This rule enforces the one-definition principle, which mandates:

  • Noninline entities shall be defined only once in a program across all translation units.

  • Inline entities shall be defined only once in a translation unit. The definitions of such entities in different translation units must be identical.

Violating the one-definition principle results in unintended implicit declarations, which leads to unexpected behavior.

Polyspace Implementation

Polyspace® reports a violation of this rule if any of these conditions are true:

  • You specify multiple definitions or tentative definitions of an identifier.

  • There are undefined global variables in your code.

  • The specialization of a template is not in the same file as the template.

  • The specialization of a template is not in the same file as the definition of the user-defined type for which the template is specialized.

  • You use a template specialization before declaring it.

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

  • The file file1.cpp contains this code:

    
    typedef signed   int          int32_t;
    
    namespace NS {
    	int32_t var; //Noncompliant
    
    	void foo(){
    		var = 0;
    		
    	}
    }; 
  • The file file2.cpp contains this code:

    
    typedef signed   int               int32_t;
    typedef signed   long long         int64_t;
    
    namespace NS {
    	int64_t var;   
    	void bar(){
    		++var;
    		
    	}
    };

The identifier var is defined in both files.

This example uses two files.

  • The file node_placements.h contains this template:

    #ifndef NODE_PLACEMENTS_H 
    #define NODE_PLACEMENTS_H 
    #include <iostream> 
    struct placed_node 
    { 
        double x_coordinate; 
        double y_coordinate; 
    }; 
    
    template <typename T> 
    struct node_position 
    { 
        T place; 
        void set_pos(T val) { 
    
            place = val; 
        } 
            void output () { 
            std::cout << "The given data type is not a valid placement.\n"; 
        } 
    }; 
     
    
    template<> 
    struct node_position<placed_node> //Compliant 
    { 
        placed_node place; 
        void set_pos(placed_node val) { 
            place = val; 
        } 
        void output () { 
            std::cout << "The position of the node is at x = " << place.x_coordinate 
            << " and y = " << place.y_coordinate << '\n'; 
        } 
    }; 
    
     
    template <typename T, typename U> 
    struct node_distance 
    { 
        T node_1; 
        U node_2; 
        void output_distance() { 
    
            std::cout << "Inputs are not valid nodes\n"; 
        } 
    }; 
    
    
    #endif 
  • The file node_distance.cpp contains specialization of the template:

    #include "node_placements.h" 
    #include <math.h>
    
    template<> 
    struct node_position<char> //Noncompliant (1) 
    { 
        char place; 
        void set_pos(char val) { 
        place = val; 
        } 
        void output() { 
        std::cout << "Please input a numerical value with the 'placed_node' type\n"; 
        } 
    }; 
    
    template<> 
    struct node_distance<placed_node, placed_node> //Noncompliant (2) 
    { 
        placed_node node_1; 
        placed_node node_2; 
        double dist; 
        void calc_dist () { 
            double x_diff = abs(node_2.x_coordinate - node_1.x_coordinate); 
            double y_diff = abs(node_2.y_coordinate - node_1.y_coordinate); 
            dist = sqrt(pow(x_diff,2.0) + pow(y_diff,2.0)); 
        } 
    	
            void output () { 
            std::cout << "The distance between the nodes is " << dist << '\n'; 
        } 
    }; 
    
     
    int main() { 
    
        node_position<int> first_pos; 
        first_pos.set_pos(3); 
        first_pos.output(); 
        placed_node node_1 = {3.5,6.5}; 
        node_position<placed_node> second_pos; 
        second_pos.set_pos(node_1); 
        second_pos.output(); 
        placed_node node_2 = {10.0, -7.3}; 
        node_distance<placed_node,placed_node> distance_measure = {node_1, node_2}; 
        distance_measure.calc_dist(); 
        distance_measure.output(); 
    } 

Putting a template and its specialization in separate files causes violations of this rule:

  • The base template node_position is declared in node_placements.h. But the char type specialization of the template is declared in node_distance.cpp. Polyspace reports a violation of this rule.

  • The template node_distance is specialized for the user-defined type placed_node in node_distance.cpp. But the user-defined type placed_node is defined in node_placements.h. Polyspace reports a violation of this rule.

  • The base template node_position and its specialization for placed_node type are both declared in the file node_placements.h. Polyspace does not report a violation.

Check Information

Group: Basic concepts
Category: Required
PQL Name: std.misra_cpp_2023.R6_2_3

Version History

Introduced in R2024b

expand all


1 All MISRA coding rules and directives are © Copyright The MISRA Consortium Limited 2021.

The MISRA coding standards referenced in the Polyspace Bug Finder™ documentation are from the following MISRA standards:

  • MISRA C:2004

  • MISRA C:2012

  • MISRA C:2023

  • MISRA C++:2008

  • MISRA C++:2023

MISRA and MISRA C are registered trademarks of The MISRA Consortium Limited 2021.