CL.ASSIGN.NON_CONST_ARG

将非常量对象传递给赋值运算符 =

这是一个类级别 (CL) 检查器,可就赋值运算符的参数类型,告知您潜在的限制或不明智的设计选择。类级别检查器会根据 Scott Meyer 的高效 C++ 规则类构造来生成建议。

CL.ASSIGN.NON_CONST_ARG 检查器会查找将非常量对象传递给运算符 = 的类。使用这种代码时,将无法表达某些语言结构。无论这些语言结构是否需要,或是否具有争议,遵循下面的基本模板,以在无论使用何种类型时均能保证语言的一致性:

复制
  class MyClass {
  public
    MyClass& operator=(const MyClass&);
  };

当赋值运算符返回时,它可返回 *this 或该运算符右侧的内容,例如:

复制
   class C{
//...
   public
     C& operator=(const C& rhs){
      return rhs;
     }
//...
   };

显然,将常量属性从没有显式 const_cast 的 rhs 删除时,不会进行编译,无论如何,这不会是什么好主意。对于这种情况,一个可能的快速解决方案(最终表明是个糟糕的方法)是仅将 rhs 参数声明为一个非常量引用:

复制
   class C{
//...
   public
     C& operator=(C& rhs){
      return rhs;
     }
//...
   };

现在,该代码将进行编译,但是此解决方案使您无法将编译器创建的临时对象分配给您的类。例如:

复制
   class C{
//...
   public
     C& operator=(C&);
     C(int);
//...
   };
//...
    C obj = 10;

在本例中,编译器将为整数构建一个常量临时对象,然后尝试找到将该常量临时对象视作输入的赋值运算符。显然,此操作将失败,因为只存在非常量赋值运算符。再一次,最好的建议还是尽可能遵循适用于赋值运算符的简单标准模板。

漏洞与风险

此设计选择不存在任何漏洞,但是有风险,即不熟悉的程序员将尝试使用“应该”正常工作但是不兼容的语言结构,并且还会遇到意义甚少或毫无意义的编译器警告(假定 C++ 编译器输出具有通常的复杂性)。

漏洞代码示例

复制
    class C{
//...
    public
       C& operator=(C& rhs){
       return rhs; 
      }
//...
    };

在此示例中,Klocwork 在第 3 行查找到一个 CL.ASSIGN.NON_CONST_ARG 错误,该错误违反了类构建规则。

修正代码示例

复制
    class C{
//...
    public
      C& operator=(const C& rhs){
       return *this; 
      }
//...
    }; 

在该修正代码示例中,运算符 = 返回 *this 并避免了违反该规则。