Submit and vote on feature ideas.

Welcome to the new Parasoft forums! We hope you will enjoy the site and try out some of the new features, like sharing an idea you may have for one of our products or following a category.

Copy Constructors and Copy Assignment Operators Static Analysis Rule [MRM-49]

choner22
choner22 Posts: 15

Rule: MRM-49-3 --> A copy constructor and a copy assignment operator shall be declared for classes that contain pointers to data items or nontrivial destructors.

This Static Analysis rule requires that I have to adhere to the Rule of 3 (now rule of 5 if moves are included). We have a destructor defined, but not the copy constructor or the copy assignment operator.

This is because I do not want my classes to be copyable, but if a user were to attempt to copy any class, the compiler will automatically generate these copiers.

So, I want to explicitly prevent the user from being able to copy any of these classes, but can not find a way to do so that eliminates the Static Analysis violation.

Here is an example of what I have attempted:

A.h
Class A
{
Public:
A(); // Constructor
Virtual ~A(); // Destructor
}

A.cpp
A::A()
{
}
A::~A()
{
}

There are 2 cases that need to be covered by my code. The handling of this case is different for code compiled prior to C++11, and code compiled C++11 and after. Both are derived from different versions of Scott Meyers Books [Next to the 2 different examples see the citations]

For C++11 and after [Effective Modern C++ Item 17]:
According to a Scott Meyers book, the following is valid code and will explicitly prevent any class that inherits from this interface from copying.

A.h
Class A
{
Public:
A(); // Constructor
Virtual ~A(); // Destructor
A(&A) = delete; // Copy Constructor
A operator=(&A) = delete; // Copy Assignment Operator
}
A.cpp remains unchanged

Even though this is entirely valid and has the desired behavior (should throw a compiler error if a user attempts to copy this class), the Static Analysis Rules engine stills throws a violations, even though I believe there shouldn't be one.

For older than C++11 [Effective C++ (Third Edition) Item 6]:

A.h
Class A
{
Public:
A(); // Constructor
~A(); // Destructor
Private:
A(&A); // Copy Constructor
A operator=(&A); // Copy Assignment Operator
}
A.cpp remains unchanged.

Because I am declaring them and making them private, this means that nothing that inherits from this interface can call it. This should also allow me to not have to define it either, because I don’t want any instances of this class being able to call it directly. This is also a valid configuration, but I still get the violation.

Is there a configuration that allows me to explicitly prevent copying, while still satisfying the rule above?

Comments

  • mstaron
    mstaron Posts: 35

    Based on your description I tested rule MRM-49 on the following examples of the code, but I didn't have any violations:
    // test1.h
    //----------------------------------------------------
    class A1
    {
    public:
    A1(); // Constructor
    virtual ~A1(); // Destructor
    A1(A1&) = delete; // Copy Constructor
    A1 operator=(A1&) = delete; // Copy Assignment Operator
    };

    class B1 : public A1 {        // No Violation
    public:
      B1();          // Constructor
      virtual ~B1(); // Destructor
    private:
      int* m1;
    };
    //----------------------------------------------------
    class A2
    {
    public:
      A2();               // Constructor
      virtual ~A2();      // Destructor
    private:
      A2(A2&);            // Copy Constructor
      A2 operator=(A2&);  // Copy Assignment Operator
    };
    
    class B2 : public A2 { // No Violation
    public:
      B2();          // Constructor
      virtual ~B2(); // Destructor
    private:
      int* m1;
    };
    //----------------------------------------------------
    // test1.cpp
    #include "test1.h"
    //----------------------------------------------------
    A1::A1()
    {
    }
    A1::~A1()
    {
    }
    
    B1::B1() : m1(new int)
    {
    }
    B1::~B1()
    {
      delete m1;
    }
    //----------------------------------------------------
    
    A2::A2()
    {
    }
    A2::~A2()
    {
    }
    
    B2::B2() : m1(new int)
    {
    }
    B2::~B2()
    {
      delete m1;
    }
    //----------------------------------------------------
    

    I used the last version of C++Test (10.4.0) and gcc 5.4 compiler.
    This rule was updated in C++Test 10.2.2 version, so for older versions it can report incorrect violations on the above code.
    If you have C++Test version 10.2.2 or higher, please specify your compiler and attach the compilable example of the code, then I could easier repeat your problem.

  • choner22
    choner22 Posts: 15

    Thanks for your reply. I however was incomplete with my question as there was a second rule that we have enabled that is currently being violated, even in your latest example.

    MRM-40 -3 -> If you define any of the copy constructor, copy assignment operator, or destructor, you might need to define one or both of the others.

    In each case, at the top of A1,B1,A2,B2.h, they all throw this violation because they require that the Copy Constructor and Copy Assignment Operator be defined.

    Everything in the original post still holds as I do not want any of my classes to be copyable.

    I am using Parasoft 10.3.4 and compiler GCC 4.9.

    Does there exist a configuration that will satisfy both rules, ensuring that neither MRM-49 and MRM-40 are violated while maintaining my desired behavior?

  • mstaron
    mstaron Posts: 35

    I confirmed that, the MRM-40 rule reports violations for copy constructors and assignment operators even if a copying is disabled. I mean they should not be reported, so I will create an internal task for this problem. C++Test does not contain other rules that can be used instead, so currently these violations can be only suppressed.