一般に、クラスのクライアント コードのインスタンス化を完全に防止するには、クラスを宣言してfinal
、
派生クラスの基本クラス サブオブジェクトのインスタンス化を防ぐためにfinal
、非public
isの場合、および抽象クラスの場合、クラスの宣言が必要です。protected
インスタンス化を部分的に禁止するには、次のことができます。
これにより、自動変数と静的変数が防止されますが、動的割り当ては防止されませんnew
。
- クラスの割り当て関数 (
operator new
) を non-にしpublic
ます。
これによりnew
、クライアント コードでの通常の -expression による動的割り当てが防止されますが、自動および静的変数、または他のオブジェクトのサブオブジェクトは提供されず::new
、グローバル割り当て関数を使用する -expression による動的割り当ては防止されません。
new
式を非常に複雑で実用的でないものにする余分な引数を持つ割り当て関数など、他の関連する手法もあります。これを一度使用して、特別なマクロを強制的に使用してオブジェクトを動的に割り当てました (例: shared-from-this class )。しかし、それは C++11 が引数の転送をサポートする前のことです。今日では、通常の関数で仕事をすることができ、そのような関数をfriend
クラスにすることができます。
コードが少なくとも 1 つのバージョンの clang コンパイラでコンパイルされるという事実は、そのコンパイラ-std=gnu++1z
のバグおよび/または言語拡張によるものです。
削除されたデフォルトのコンストラクターを呼び出すため、コードはコンパイルされません。また、MinGW g++ 5.1.0 などではコンパイルできません-std=gnu++1z
。
コードが少なくとも 1 つのバージョンの clang コンパイラでコンパイルされるという事実は、そのコンパイラ-std=gnu++1z
のバグおよび/または言語拡張が原因である可能性があります。正しい動作が何であるかは不明です。
コードは clang および Visual C++ 2015 でコンパイルされますが、たとえば MinGW g++ 5.1.0 ではコンパイルされません-std=gnu++1z
。
直観的にdelete
は、コードをコンパイルする必要がある場合は意味がありませんが、C++ では多くの無意味な構造が許可されています。
問題は、クラスが集約であるかどうか (その場合、式は集約の初期化を実行します) です。これは、削除された既定のコンストラクターがユーザー提供のnew
と見なすことができるかどうかにかかっています。また、ユーザーTartanLlamaがコメントで説明しているように、ユーザー提供の要件は次のとおりです。
C++11 §8.4.2/4
特別なメンバー関数は、ユーザーが宣言し、最初の宣言で明示的にデフォルト設定または削除されていない場合、ユーザー提供です。
つまりdelete
、この質問の例のデフォルトのコンストラクターはそのコンストラクターを宣言していますが、それはユーザー提供ではないため (他のメンバーについても同様です)、クラスは集約です。
この文言に関して私が見つけることができる唯一の欠陥レポートはDR 1355ですが、これは単に「特別なメンバー」という言葉の使用に関する問題に関係しており、それらの言葉を削除することを提案しています。しかし、この質問によって実証された効果と、関数を最初の宣言でのみ削除できることの両方を考慮すると、言葉遣いは奇妙です。
まとめると、正式には C++11 の時点で (C++14 はチェックしていません)、コードはコンパイルされるはずです。しかし、これは文言が意図を反映していないため、標準の欠陥である可能性があります。また、MinGW g++ 5.1.0 はコードをコンパイルしないため、2015 年 10 月現在、コードのコンパイルに依存することはお勧めできません。