Non-Compliant Code Example
Consider a design that attempts to seize and release an object's resources through a calls to virtual functions from a base class's constructor and destructor.
class B {
public:
B() { seize(); }
virtual ~B() { release(); }
protected:
virtual void seize() {}
virtual void release() {}
};
class D : public B {
public:
D() {}
~D() {}
protected:
void seize() {
B::seize();
// get derived resources...
}
void release() {
// release derived resources...
B::release();
}
};
D x;
The result of running this code is that no derived class resources will be seized or released during the initialization and destruction of the x object. At the time of the call to seize in the initialization of x, the D constructor has not been entered, and the behavior of the under-construction x object will be to invoke B::seize rather than D::seize. A similar situation occurs for the call to release in the base class destructor. If the functions seize and release were declared to be pure virtual functions, the result would be undefined behavior.
Compliant Solution
The value of the expression i++ is not used in a larger expression, and so either prefix of postfix ++ would produce the same result. Therefore the prefix form is preferred.
template <class Cont>
void iterate( Cont &c ) {
typedef typename Cont::iterator I;
for( I i(c.begin()); i != c.end(); ++i )
//...
}
Risk Assessment
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
|---|---|---|---|---|---|
EXP10-A |
1 (low) |
1 (unlikely) |
2 (medium) |
P2 |
L3 |
References
[[Sutter 04]] Item 28: Prefer the canonical form of ++ and --. Prefer calling the prefix forms.