C++11 で関数をデフォルトにすることに何の意味があるのでしょうか?
-
05-07-2019 - |
質問
C++11 では、コンパイラに次のことを指示する機能が追加されています。 デフォルトの実装を作成する いずれかの 特別なメンバー関数. 。関数を削除する価値はわかりますが、関数を明示的にデフォルトにする価値はどこにあるのでしょうか?空白のままにしておけば、コンパイラがそれを実行します。
私が確認できる唯一の点は、デフォルトのコンストラクターは、他のコンストラクターが存在しない場合にのみ作成されるということです。
class eg {
public:
eg(int i);
eg() = default;
};
しかし、それは本当に今のやり方よりも良いのでしょうか?
class eg {
public:
eg(int i);
eg() {}
};
それともユースケースが欠けているのでしょうか?
解決
デフォルトのコンストラクターには宣言があり、その宣言には通常のアクセス規則が適用されます。例えば。デフォルトのコピーコンストラクタを保護することができます。これらの新しい宣言がない場合、デフォルトで生成されるメンバーはパブリックです。
他のヒント
StroustrupのWebサイトの例は、この点を理解するのに役立つ可能性があります。
デフォルトおよび削除された機能-デフォルトの制御
"禁止することの一般的なイディオム コピー"今表現することができます 直接:
class X { // ... X& operator=(const X&) = delete; // Disallow copying X(const X&) = delete; };
逆に、明示的に言うこともできます デフォルトのコピー動作にすること:
class Y { // ... Y& operator=(const Y&) = default; // default copy semantics Y(const Y&) = default; };
デフォルトについて明示することは 明らかに冗長ですが、へのコメント その効果と(悪い)ユーザー コピー操作を明示的に定義する デフォルトの振る舞いを与えるためのものです 珍しくありません。に任せる デフォルトを実装するコンパイラ 動作がよりシンプルで、エラーが発生しにくく、 多くの場合、オブジェクトコードの改善につながります。 " default"メカニズムを使用できます デフォルトがある関数の場合。 "削除"メカニズムは 任意の機能。たとえば、次のことができます のような望ましくない変換を排除する これ:
struct Z { // ... Z(long long); // can initialize with an long long Z(long) = delete; // but not anything less };
生成された関数のアクセシビリティ (プライベート/保護) を変更できるだけでなく、関数を仮想化することもできます。
struct S
{
virtual ~S();
virtual S& operator=(const S&);
};
S::~S() = default;
S& S::operator=(const S&) = default;
デフォルトの関数の次の側面を変更できます。
- アクセス(非公開)
- バーチャル
- 明示的 (コンストラクター)
- 例外仕様
- パラメータの定数性
ただし、そのためには、関数をクラスの外で定義する必要があります (8.4.2/2)。 C++0x 最終委員会草案).
ローレンス・クロウルによるオリジナルの提案のバージョンは次のとおりです。 ここ.
おかげで ロジャー・ペイト 説明と引用のために。
1)暗黙的に生成されたデストラクタは現在仮想ではありません。そのため、仮想化するために定義する必要がありますが、その場合は効率的ではありません。 = defaultを使用すると、暗黙的に生成されるデストラクタとして仮想と効率の両方が得られます。
2)暗黙的に生成されたものとは反対に、アクセス指定子を持ちます。
3)デフォルトのコンストラクターをインライン化しても、クラスはまだ単純なままです。
デフォルトでコピーコンストラクタを生成できると便利だと思います。あなたが入力する実装が短くなると言うので、デフォルトのコンストラクタを生成するデフォルトの使用を見ることができません。
Scott Meyerのすばらしい本の項目17を参照" 効果的なモダンC ++ "。デフォルトのコピーコンストラクタ、コピー操作、および移動操作が生成される(または生成されない)多くの条件について説明します。
言い換えれば、コンパイラは「とにかくやらない」かもしれません。しかし、デフォルトの特別なメンバー関数が理にかなっている場合、ユーザーは" default"を使用できます。それ以外の場合は生成されないデフォルト関数を生成するようコンパイラーに明示的に指示するキーワード。
項目17の最後にある「覚えておくべきこと」から:
移動操作は、明示的に宣言された移動操作、コピー操作、またはデストラクターがないクラスに対してのみ生成されます。
コピーコンストラクターは、明示的に宣言されたコピーコンストラクターがないクラスに対してのみ生成され、移動操作が宣言されると削除されます。コピー割り当て演算子は、明示的に宣言されたコピー割り当て演算子がないクラスに対してのみ生成され、移動操作が宣言されると削除されます。デストラクタが明示的に宣言されているクラスでのコピー操作の生成は非推奨です。
私にとっては便利な無効化機能です。現在作成しているほとんどのクラスでは、&割り当て-リンカエラーに依存するのではなく、コンパイラがこれを行うために認識できる機能があると便利です。
多数の属性を持つクラスがある場合、デフォルトはコピーコンストラクターにより便利です。 たとえば、次のクラスがある場合:
class MyClass {
private:
int offset;
std::string name;
std::vector<Person*> relatives;
float weight;
MyClass* spouse;
Vehicle* car;
double houseArea;
Date birth;
Person* parents[2];
public:
/* Default constructor will be defined here */
};
この方法でコピーコンストラクタを定義する代わりに:
MyClass(const MyClass& that) :
offset(that.offset),
name(that.name),
relatives(that.relatives),
weight(that.weight),
spouse(that.spouse),
car(that.car),
houseArea(that.houseArea),
birth(that.birth),
parents(that.parents)
{}
この方法で定義します:
MyClass(const MyClass&) = default;