Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

It is often recommended that class objects be initialized using direct constructors rather than assignment. [Meyers 01] Direct constructors avoids construction, copying, and destruction of a temporary copy of the object. To wit, object should be constructed this way:

Code Block
bgColor#ccccff
langcpp
Widget w( /* constructor arguments */);

rather than this way:

Code Block
bgColor#ffcccc
langcpp
Widget w = Widget( /* constructor arguments */);

or this way (for classes that support this syntax)

Code Block
bgColor#ffcccc
langcpp
Widget w = /* constructor argument */;

Besides being inefficient, this last syntax violates OOP09-CPP. Ensure that single-argument constructors are marked "explicit".

However, C++ parsers are often liable to misparsing constructor arguments. While compilers will often generate a compiler error upon such misparses, it is possible for such misparses to slip past a compiler and lurk in executable code, with unexpected results.

Non-Compliant Code Example

possible to devise syntax which can ambiguously be interpreted as either an expression statement or a declaration. Syntax of this sort is referred to as a vexing parse because the compiler must use disambiguation rules to determine the semantic results. The C++ Standard, [stmt.ambig], paragraph 1, states in part [ISO/IEC 14882-2014]:

There is an ambiguity in the grammar involving expression-statements and declarations: An expression-statement with a function-style explicit type conversion as its leftmost subexpression can be indistinguishable from a declaration where the first declarator starts with a (. In those cases the statement is a declaration. [Note: To disambiguate, the whole statement might have to be examined to determine if it is an expression-statement or a declaration. ...

A similarly vexing parse exists within the context of a declaration where syntax can be ambiguously interpreted as either a function declaration, or a declaration with a function-style cast as the initializer. The C++ Standard, [dcl.ambig.res], paragraph 1, states in part:

The ambiguity arising from the similarity between a function-style cast and a declaration mentioned in 6.8 can also occur in the context of a declaration. In that context, the choice is between a function declaration with a redundant set of parentheses around a parameter name and an object declaration with a function-style cast as the initializer. Just as for the ambiguities mentioned in 6.8, the resolution is to consider any construct that could possibly be a declaration a declaration.

Do not write a syntactically semantically ambiguous declaration, including vexing parses. With the advent of uniform initialization syntax using a braced-init-list, there is now syntax that unambiguously specifies a declaration instead of an expression statement. Declarations can also be disambiguated by using nonfunction-style casts, initialization using =, or by removing extraneous parenthesis around the parameter name.

Noncompliant Code Example

In this noncompliant code example, an attempt is made to declare a local variable, w, of type Widget while executing the default constructor. However, this is syntactically ambiguous where the code could either be a declaration of a function pointer accepting no arguments and returning a Widget, or a declaration of a local variable of type WidgetIn this non-compliant example, the class Widget has a default constructor.

Code Block
bgColor#FFCCCC
langcpp
class#include <iostream>
 
struct Widget {
public:
  explicit Widget() {cerr std::cout << "constructedConstructed" << std::endl;}
};

int 
void mainf() {
  Widget w();
  return 0;
}

However, while a human may consider w to be explicitly built with the default constructor, the compiler interprets w to be a pointer to a function that takes no arguments, and returns a Widget!

As a result, this program compiles and prints no output, because the default constructor is never actually invoked.

Compliant Solution

This situation is ameliorated by removing the parentheses after w.

...

Running this program produces the single output constructed.

Non-Compliant Code Example

Here is a more complex non-compliant example. The class Widget maintains a single int, and the class Gadget maintains a single Widget.

...

As a result, this program compiles cleanly and prints only 3 as output, because no Gadget or Widget is constructed.

Compliant Solution

This situation is ameliorated by moving the Widget construction outside Gadget.

...

widget constructed
gadget constructed
3

Risk Assessment

Not guarding implicit constructor parsing could lead to unexpected behavior.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

OOP31-CPP

low

likely

low

P9

L2

Automated Detection

Tool

Version

Checker

Description

 PRQA QA-C++

 
Include Page
PRQA QA-C++_v
PRQA QA-C++_v

2510

 

 

Bibliography

  • [Meyers 01] Item 6: Be alert for C++'s most vexing parse.

...