Main Content

MISRA C++:2023 Rule 6.2.3

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

Since R2024b

Description

Rule Definition

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

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 declare an extern object in multiple files.

  • 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:

    #include "header.hpp"
    extern int flag;    // Noncompliant
    class A{/**/};
    void foo(void){
    	//..
    } 
  • The header header.hpp contains this declaration:

    extern int flag;

The external identifier flag is declared in both header.hpp and file1.cpp. Polyspace reports a violation of this rule.

  • The file file1.cpp contains this code:

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

    typedef signed   int               int32_t;
    typedef signed   long long         int64_t;
    
    namespace NS {
    	extern int64_t var;   // Noncompliant
    	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

Version History

Introduced in R2024b