C +の中で= delete指定子を使用する3つの方法


このポストでは、C +でdeleteの指定子を使用できる3つの異なる方法を発見します.どうやって見るか
  • は、オブジェクトをコピーするのを許すことができます
  • あなたが関数呼び出し
  • のためにどんな種類の暗黙の転換を許容するかについて制限することができます
  • あなたが
  • を許すどんな種類のテンプレートインスタンスを制限することができますか

    どのようにコピーを禁止する/クラスの移動?
    答えを最初の質問はなぜそのような機能が必要ですか?クラスをコピーしたり移動させたりする必要はないかもしれません.ですから、関連する特殊関数を呼び出し元に到達できません.
    これを達成するために、遺産と現代のオプションがあります.
    レガシーオプションは、プライベートまたはプロテクトとして宣言することです.
    class NonCopyable {
    public:
      NonCopyable() {/*...*/}
      // ...
    private:
      NonCopyable(const NonCopyable&); //not defined
      NonCopyable& operator=(const NonCopyable&); //not defined
    };
    
    C++ 11以前には、不要な特殊関数を宣言したり、実装したりしない以外のオプションはなかった.このように、オブジェクトをコピーすることを禁止することができました(時間内に戻って利用可能な移動意味論はありませんでした).実装/定義の欠如はメンバー関数、友人、またはアクセス指定子を無視するときに誤った使用に対して役立ちます.それはコンパイル時の失敗を引き起こしません、あなたは時間をリンクする際に問題に直面します.
    C++ 11では、単に= delete;と宣言して削除することができます
    class NonCopyable {
    public:
      NonCopyable() {/*...*/}
      NonCopyable(const NonCopyable&) = delete;
      NonCopyable& operator=(const NonCopyable&) = delete;
      // ...
    private:
      // ...
    };
    
    C++ 11の方法はより良いアプローチです
  • は、開発者
  • によって誤りであるかもしれない個人のセクションの機能を持つことより明白です
  • 場合は、コピーをしようとすると、コンパイル時にエラーが発生しました
  • 削除された関数はpublicではなくprivateとして宣言されるべきです.場合によっては、いくつかのコンパイラは、プライベート関数を呼び出すだけではなく、削除された1つについて文句を言うかもしれません.

    関数呼び出しのために暗黙の転換を禁止する方法?
    整数値をとる関数があります.全体の数.どのように多くの人々が車に座ることができるパラメータとして取るとしましょう.それは2であるかもしれません、若干の贅沢な車のためにいくつかの奇妙な3人のシーターがあります.4.9ではない.それは5.1ではないまたは5でもない半分.5です.私たちは体の部分をトラフィックしないでください.
    どのように、あなたはパラメータとして全体の数字を受け取るだけを強制することができますか?
    明らかに、整数パラメータを取るでしょう.intunsigned、あるいはshortかもしれない.オプションがたくさんあります.おそらく、numberOfSeatsパラメタが整数でなければならないという文書さえあります.
    すごい!
    それで、クライアントの呼び出しがまだフロートを通過するならば、何が起こりますか?
    #include <iostream>
    
    void foo(int numberOfSeats) {
        std::cout << "Number of seats: " << numberOfSeats << std::endl;
        // ...
    }
    
    int main() {
        foo(5.6f);
    }
    /*
    Number of seats: 5
    */
    
    浮動小数点パラメータは受け入れられ、整数に絞り込まれます.それが丸められていると言うことさえできません、それは暗黙のうちに変換されて、整数に絞り込まれます.
    あなたは、これが罰金であると言うかもしれません、そして、特定の状況で、それは多分あります.しかし、他では、この振舞いは単に受け入れられません.
    このような場合はどうすればよいのですか.
    あなたは呼び出し側でそれを扱うかもしれませんがfooがしばしば使われるならば、それは各々の呼び出しでチェックをするのを退屈します、そして、コードレビューは十分に信頼できません、
  • が外部の世界によって使用されるAPIの一部であるならば、それはあなたのコントロールからあります.
  • 前のセクションで見たように、C++ 11以降では、特定のタイプをコピーまたは移動するのを制限するために、fooの指定子を使用できます.しかし、deleteは、より多くのために使用することができます.これは、任意の関数、メンバーやスタンドアロンに適用することができます.
    浮動小数点数から暗黙の変換を許可したくない場合は、単にfooのオーバーロードされたバージョンをfloatで削除できます.
    #include <iostream>
    
    void foo(int numberOfSeats) {
        std::cout << "Number of seats: " << numberOfSeats << std::endl;
        // ...
    }
    
    void foo(double) = delete;
    
    int main() {
        // foo(5);
        foo(5.6f);
    }
    
    /*
    main.cpp: In function 'int main()':
    main.cpp:12:13: error: use of deleted function 'void foo(double)'
       12 |     foo(5.6f);
          |             ^
    main.cpp:8:6: note: declared here
        8 | void foo(double) = delete;
          |      ^~~
    */
    
    ET voila!フランス人が言うように.それです.関数のオーバーロードを削除することで、特定の型からの暗黙の変換を禁じることができます.ここで、ユーザーがAPIを通過できるパラメータの型を完全に制御できます.

    テンプレートの特定のインスタンス化を禁止する方法
    このようなアプローチもテンプレートで動作するので、特定の型のテンプレート関数のインスタンスを無効にすることができます.
    template <typename T>
    void bar(T param) { /*..*/ }
    
    この関数を呼び出した場合は、整数としましょう.
    bar<int>(42);
    
    ただし、= deleteでインスタンス化を削除することができます.
    #include <iostream>
    
    template <typename T>
    void bar(T param) { /*..*/ }
    
    template <>
    void bar<int>(int) = delete;
    
    int main() {
        bar<int>(5);
    }
    /*
    main.cpp: In function ‘int main()’:
    main.cpp:10:15: error: use of deleted function ‘void bar(T) [with T = int]’
       10 |     bar<int>(5);
          |               ^
    main.cpp:7:6: note: declared here
        7 | void bar<int>(int) = delete;
          |      ^~~~~~~~
    */
    
    ちょうどintTが異なるタイプであると心に留めておいてください、そして、あなたが1を削除するならば、あなたはあまりにも他を削除することを考慮するべきです.これは、関数のオーバーロードを削除するときではなく、テンプレートに対してのみ有効です.

    結論
    今日、私たちはC++ 11から利用可能なconst Tの指定子を使用する方法を3つ見ました.私たちは、クラスを非コピー可能な/または非機能的にその助けを借りて作成することができますが、我々はまた、関数のパラメータのための暗黙の変換を禁止することができますし、任意のタイプのテンプレートのインスタンスを無効にすることもできます.それはタイトな、厳しいを作成する素晴らしいツールです.