OOP53-CPP. 按照规范顺序编写构造函数的成员初始化
原文链接:
OOP53-CPP. Write constructor member initializers in the canonical order
类构造函数的成员初始化允许成员被初始化为指定的值,和调用指定参数的基类构造函数。然而,初始化发生的顺序是固定的,并且不依赖所写的成员初始化列表的顺序。 C++ 标准, [class.base.init], 段 11 [ISO/IEC 14882-2014], 陈述如下:
In a non-delegating constructor, initialization proceeds in the following order:
— First, and only for the constructor of the most derived class, virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.
— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).
— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).
— Finally, the compound-statement of the constructor body is executed.
[Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. —end note]
所以,成员初始化的顺序与出现在成员初始化列表中的顺序是不相关的。成员被初始化的顺序,包括基类初始化,取决于类成员变量或者基类修饰符列表被声明的顺序。不遵循规范顺序编写成员初始化能导致 未定义行为,undefined behavior,比如读取未初始化内存。
始终按照规范顺序编写构造函数中成员的初始化:首先是在出现在类的 base-specific-list
的直接基类的顺序,然后是在类定义中被声明的非静态数据成员顺序。
不合规代码示例
在这个不合规代码代码示例中,C::C()
的成员初始化列表试图先初始化 someVal
,然后初始化依赖于 someVal
的 dependsOnSomeVal
的值。因为成员变量的声明顺序于成员初始化顺序不匹配,试图读取 someVal
的值导致 不确定值,unspecified value 存储到 dependsOnSomeVal
。
1 | class C { |
合规方案
该合规方案改变了类成员变量定义的顺序,以便于在构造函数成员初始化列表中的依赖项可以按照正确排序。
1 | class C { |
依赖之前已被初始化的值对于初始化器来说是合理的。
不合规代码示例
在这个不合规的代码示例中,派生类, D
,试图从基类,B2
获取的值来初始化基类,B1
。然而,因为基于基类修饰符列表定义的顺序, B1
在 B2
之前初始化,该行为的行为是 未定义的,undefined.
1 | class B1 { |
合规方案
该合规方案使用从构造函数参数列表中获取的值来初始化两个基类,二不是依赖基类初始化的顺序。
1 | class B1 { |
例外
OOP53-CPP-EX0: 构造函数如果不使用成员初始化则不违反此规则。
Risk Assessment
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
OOP53-CPP | Medium | Unlikely | Medium | P4 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Tool | Version | Checker | Description |
Astrée | 20.10 | **initializer-list-order ** | Fully checked |
Axivion Bauhaus Suite | 7.2.0 | CertC++-OOP53 | |
Clang | 3.9 | -Wreorder |
|
CodeSonar | 6.2p0 | LANG.STRUCT.INIT.OOMI | Out of Order Member Initializers |
Helix QAC | 2022.1 | C++4053 | |
Klocwork | 2022.1 | CERT.OOP.CTOR.INIT_ORDER | |
LDRA tool suite | 9.7.1 | 206 S** ** | Fully implemented |
Parasoft C/C++test | 2021.2 | CERT_CPP-OOP53-a | List members in an initialization list in the order in which they are declared |
Polyspace Bug Finder | R2021b | CERT C++: OOP53-CPP | Checks for members not initialized in canonical order (rule fully covered) |
PRQA QA-C++ | 4.4 | **4053 ** | |
RuleChecker | 20.10 | **initializer-list-order ** | Fully checked |
SonarQube C/C++ Plugin | 4.10 | S3229 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
[ISO/IEC 14882-2014] | Subclause 12.6.2, “Initializing Bases and Members” |
---|---|
[Lockheed Martin 2005] | AV Rule 75, Members of the initialization list shall be listed in the order in which they are declared in the class |
本文标题:OOP53-CPP. 按照规范顺序编写构造函数的成员初始化
文章作者:xwnb
发布时间:2022-04-03
最后更新:2023-04-17
原始链接:https://xwnb.github.io/posts/3904355907/
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!并保留本声明。感谢您的阅读和支持!
分享