CodeQL 文档

复制构造函数和赋值运算符定义不一致(“二法则”)

ID: cpp/rule-of-two
Kind: problem
Security severity: 
Severity: warning
Precision: high
Tags:
   - reliability
   - readability
   - language-features
Query suites:
   - cpp-security-and-quality.qls

点击查看 CodeQL 代码库中的查询

此规则查找定义了复制构造函数或复制赋值运算符,但未同时定义两者。编译器会为这些函数生成默认实现,由于它们处理的是类似的关注点,因此如果其中一个的默认实现不能令人满意,则另一个也可能不能令人满意。

当一个类定义了复制构造函数或复制赋值运算符,但未同时定义两者时,可能会导致意外的行为。对象初始化(即,Class c1 = c2)的行为可能与对象赋值(即,c1 = c2)的行为不同。

建议

首先,考虑用户定义的成员是否需要显式定义。如果类没有提供用户定义的复制构造函数,则编译器将始终尝试生成一个公共复制构造函数,该构造函数递归调用每个字段的复制构造函数。如果现有的用户定义的复制构造函数执行完全相同的操作,则最有可能是删除它。编译器生成的版本可能更高效,并且不需要随着字段的添加和删除而手动维护。

如果用户定义的成员 *确实* 需要存在,则应定义另一个对应的成员。如果编译器生成的实现可以接受,则可以使用 = default 将其定义为默认的,或者如果它不应该被调用,则可以使用 = delete 将其定义为删除的。

示例

class C {
private:
	Other* other = NULL;
public:
	C(const C& copyFrom) {
		Other* newOther = new Other();
		*newOther = copyFrom.other;
		this->other = newOther;
	}

	//No operator=, by default will just copy the pointer other, will not create a new object
};

class D {
	Other* other = NULL;
public:
	D& operator=(D& rhs) {
		Other* newOther = new Other();
		*newOther = rhs.other;
		this->other = newOther;
		return *this;
	}

	//No copy constructor, will just copy the pointer other and not create a new object
};

参考资料

  • ©GitHub, Inc.
  • 条款
  • 隐私