CERT.DCL.AMBIGUOUS_DECL

構文的に曖昧な宣言を記述しないでください。

式ステートメントとも宣言とも解釈できる曖昧な構文を記述できます。

脆弱性とリスク

この種の構文では、コンパイラは曖昧性解消規則を使用して意味的結果を判断する必要に迫られます。このため、この種の構文は「厄介な解析」と呼ばれます。

軽減と防止

構文的に曖昧な宣言を記述しないでください。

例 1

コピー
  #include <mutex>
  #include <iostream>
  
  static std::mutex m;
  static int shared_resource;
  
  struct Widget1 {
    Widget1() { std::cout << "Constructed" << std::endl; }
  };
 
 struct Widget2 {
   explicit Widget2(int i) { std::cout << "Widget2 constructed" << std::endl; }
 };
 
 struct Gadget {
   explicit Gadget(Widget2 wid) { std::cout << "Gadget constructed" << std::endl; }
 };
 
 void increment_by_42() {
   std::unique_lock<std::mutex>(m);    //Noncompliant Code
   shared_resource += 42;
 }
 
 void f1() {
   Widget1 w1();                       //Noncompliant Code
 }
 
 void f2() {
   int i = 3;
   Gadget g(Widget2(i));               //Noncompliant Code
   std::cout << i << std::endl;
 }

20 行目の宣言は構文的に曖昧です。この宣言は、匿名オブジェクトを宣言して、単一の引数をとるその変換コンストラクターを呼び出すと解釈することも、m というオブジェクトを宣言し、これをデフォルト構築すると解釈することもできます。この例で使用されている構文は前者ではなく後者を定義しているため、ミューテックスオブジェクトがロックされることはありません。

25 行目の宣言は構文的に曖昧です。この行のコードは、引数を受け入れずに Widget を返す関数ポインターの宣言である可能性も、Widget 型のローカル変数の宣言である可能性もあります。この例で使用されている構文は、後者ではなく前者を定義しています。

30 行目の宣言 Gadget g(Widget(i)); は、単一の引数を持つ Gadget オブジェクトの宣言としては解析されません。この宣言は、パラメーターに冗長な括弧が付いた関数宣言として解析されます。

例 2

コピー
  #include <mutex>        
  #include <iostream>
  static std::mutex m;
  static int shared_resource;
  
  struct Widget1 {
    Widget1() { std::cout << "Constructed" << std::endl; }           
  };
  struct Widget2 {
   explicit Widget2(int i) { std::cout << "Widget constructed" << std::endl; }
 };
 
 struct Gadget {
   explicit Gadget(Widget2 wid) { std::cout << "Gadget constructed" << std::endl; }
 };
 
 void increment_by_42() {
   std::unique_lock<std::mutex> lock(m);
   shared_resource += 42;
 }
 
 void f1() {
   Widget1 w1; // Elide the parentheses
   Widget1 w2{}; // Use direct initialization
 }
 
 void f2() {
   int i = 3;
   Gadget g1((Widget2(i))); // Use extra parentheses
   Gadget g2{Widget2(i)}; // Use direct initialization
   std::cout << i << std::endl;
 }

この例は、例 1 の不適合コードを修正する方法を示しています。