C++11の新機能① | C++11の共通キーワードを詳しく解説

目次

1 はじめに

2. C++11の新キーワードの詳細説明

2.1、自動

2.2、オーバーライド

2.3、決勝

2.4、nullptr

2.5. =delete を使用してオブジェクトのコピーを防止する

2.6、decltype

2.7、例外なし

2.8、constexpr

2.9、static_assert


VC++共通機能開発まとめ(コラム記事一覧、購読歓迎、継続更新…)icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/124272585 C++ソフトウェア例外トラブルシューティング入門から習得までシリーズチュートリアル(コラム記事)リスト、購読へようこそ、更新し続けます...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/article/details/125529931エントリーからマスタリー事例集までの C++ ソフトウェア分析ツール (コラム記事は更新中...) icon-default.png?t=N7T8https :/ /blog.csdn.net/chenlycly/article/details/131405795 C/C++ の基本と上級 (コラム記事、継続的に更新...) icon-default.png?t=N7T8https://blog.csdn.net/chenlycly/category_11931267.html        C++ 11 新規機能は非常に重要です。C++ 開発者として学習する必要があります。筆記試験や面接だけでなく、オープンソース コードで大規模に使用されることもあります。多くのビデオ会議やライブ ブロードキャスト ソフトウェアで使用されているオープン ソースの WebRTC プロジェクトを例に挙げると、C++11 以降の新機能が WebRTC コードで広く使用されています。そのソース コードを理解するには、これらの新機能を理解する必要があります。 C++。したがって、次の期間では、参考または参照のために、私の仕事の実践を組み合わせて C++11 の新機能について詳しく説明します。

1 はじめに

       C++ 言語の柔軟性と効率を向上させるために、C++11 では auto、overide、final、nullptr、decltype、constexpr、noexc、static_assert などの複数のキーワードが導入されています。この記事では、コーディングの実践を組み合わせて、主に C++11 で導入された一般的に使用される新しいキーワードを紹介します。

C++11 以降の新しい標準には多くの新機能が導入されており、これにより C++ の柔軟性が高まりますが、同時に C++ の機能が肥大化し、C++ の制御が難しくなります。

2. C++11の新キーワードの詳細説明

2.1、自動

       プログラミングでは、式の値を変数に代入する必要があることがよくあります。そのためには、変数を宣言するときに式の型を明確に示す必要がありますが、判断が難しい場合があります。C++11 標準では auto 型指定子が導入されており、これによりコンパイラが式の型を分析できるようになります。コンパイラは初期値から auto 変数の型を推測する必要があるため、auto 変数を初期化する必要があります。

       自動型推定。初期化式から変数のデータ型を推定するために使用されます (実際には、型推定はコンパイル時に変数に対して実行されるため、プログラムの実行効率には悪影響を及ぼしません)。例は次のとおりです。

auto i = 2;      // int类型
auto d = 1.0;  //  double类型
auto str = "hello word"; // const char*
auto ch =  'A';   // char类型
auto func = less<int>();  // 函数指针
vector<int> vtList; 
auto iter = vtList.begin();  // 选代器类型
auto p = new foo();         // 自定义类型 

2.2、オーバーライド

       派生クラスが基本クラスの仮想関数を書き換えるとき、関数の前に virtaul マークを追加できるため、このマークを見た後にその関数が基本クラスを書き換える仮想関数であることがわかります。C++11 で override キーワードが導入された後、override を使用して書き換えられた関数をより明確に識別できるようになりました。

       派生クラスの関数にオーバーライド フラグを追加する利点は、プログラマが基本クラスを書き直す意図を明確にする一方で、コンパイラがいくつかのエラーを検出できるようになることです。オーバーライドを使用して派生クラスの特定の関数をマークしますが、その関数が基本クラスの仮想関数をオーバーライドしない場合、コンパイラはエラーを報告します。

class Base
{
public:
    virtual void func() const
    {
        cout << __func__ << std::endl;
    }
}

class Derived :public Base
{
public:
    virtual void func() overide
    {
        cout << __func__ << std::endl;
    }
}

2.3、決勝

       場合によっては、他のクラスに継承させたくないクラスを定義する必要があります。または、基本クラスとして適切かどうかを考えたくない。この目的を達成するために、C++11 では継承を防止するためのキーワード Final が導入されており、このキーワードをクラス名の後ろに置くとクラスを継承できなくなります。例は次のとおりです。

class Base{ /*   */};
class Last final : public Base { /*   */};

        このキーワードを使用してクラスのメンバー関数を変更し、関数が派生クラスによってオーバーライドされるのを防ぐこともできます。

class Base
{
public:
    virtual void func() const
    {
        cout << __func__ << std::endl;
    }
}

class Derived :public Base
{
public:
    virtual void func() overide final
    {
        cout << __func__ << std::endl;
    }
}

2.4、nullptr

       Nullptr は、C++ における NULL の曖昧さを解決するために導入された新しい型です。NULL は実際には 0 を表すためです。ポインターを初期化するにはリテラル値 nullptr を使用し、現在 null ポインターであることを示すのが最善です。nullptr は、他のポインター型に変換できる特別な型のリテラルです。

       nullptr が NULL の曖昧さを解決できると言われるのはなぜですか? 例を見てみましょう。

void func( int );
void func( int* );

たとえば、上記の 2 つのオーバーロードされた関数では、func 関数を呼び出す必要があります。NULL が渡された場合 (NULL は実際には 0 を表し、暗黙的に void* に変換してから int* に変換できます)、両方の関数を次のように実行できます。コンパイラはどれを呼び出すべきかを認識せず、曖昧さが生じ、コンパイル時にエラーが報告されます。nullptr パラメーターが渡されると、コンパイルではエラーが報告されず、 void func(int*) が呼び出されていることがより明確になります。    

       nullptr_t は変数型で、その値は nullptr です。nullptr_t の定義を確認できます。

#ifdef __cplusplus
    namespace std
    {
        typedef decltype(__nullptr) nullptr_t;  // nullptr_t被声明为__nullptr的类型
    }

    using ::std::nullptr_t;
#endif

関数のパラメータに nullptr_t がある場合、変数名を指定する必要はなく、関数本体の対応するパラメータを nullptr に設定するだけです。例として、shared_ptr スマート ポインターの特定のコンストラクターを取り上げます。(コードは、Visual C++ のスマート ポインターのソース コード実装から取得されます)。

template<class _Dx,
    class _Alloc,
    enable_if_t<conjunction_v<is_move_constructible<_Dx>,
    _Can_call_function_object<_Dx&, nullptr_t&>
               >, int> = 0>
shared_ptr(nullptr_t, _Dx _Dt, _Alloc _Ax)  // 参数类型为nullptr_t,对应的值就是nullptr
{    // construct with nullptr, deleter, allocator
    Setpda(nullptr, _STD move(_Dt), _Ax);
}    

2.5. =delete を使用してオブジェクトのコピーを防止する

       実際、この場所の =delete はキーワードではありません。

       新しい C++11 標準では、コピー コンストラクターとコピー コピー関数を削除された関数として定義することで、コピーを防止します。関数の後に =delete を追加すると、その関数は削除された関数になります。削除された関数については、宣言はしていますが、使用することはできません。

       スマート ポインター クラス std::unique_ptr を例にとると、このスマート ポインター クラスはコピー構築と割り当て操作をサポートしていませんが、主に所有権の転送操作をサポートしています。したがって、クラスの定義で、クラスのコピー コンストラクターと代入関数を =delete 関数に設定して、コピーの構築と代入を防止します。 (これは典型的なインタビューの質問です: std::unique_ptr スマート ポインターはどのようにコピーと代入を禁止しますか?コピーした?)

unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;

コピー コンストラクターと代入関数を実装しないとこの目標を達成することはできません。これら 2 つの関数を実装しないと、コンパイラがデフォルトのコピー コンストラクターと代入関数を自動的に生成するためです。

       C++ =delete フラグが存在しない前は、コピー コンストラクターと代入関数をプライベートとして設定できるため、これら 2 つの関数をクラス外で使用できません。

2.6、decltype

       式の型によって定義される変数の型を推測したいが、変数の型を推測するために変数を初期化するために式の値を使用したくない場合があります。要件に応じて、C++11 標準では decltype 型インジケーターが導入されており、その役割はオペランドのデータ型を推論してそれを返すことです。コンパイラーは推論された式の型を分析するだけで、式の値は計算しません (式は評価されません)。

const int nVal = 0;
decltype(nVal) y = 1;
decltype(t + u); // 其中t和u是数据类型,不对表达式t+u进行求值,只去推断t+u表达式的数据类型。

       型指定子は指定された式の型を生成し、その型はコンパイル時に式の型に従って推定されます。例は次のとおりです。

int i;
struct A
{
    double x; 
};
const A* a = new A();

decltype(i)            x2; // int
dec1type (a->x)       x3; // double
dec1type((a->x))       x4;   // double&

2.7、例外なし

       C++11 標準では、関数が例外をスローしないことを指定する noexc キーワードが提供されています。次のように、このキーワードを関数のパラメータ リストの後に置きます。

void func() noexcept;            // 这里noexcept作为修饰符

関数が例外をスローしないことを事前に知っておくことは、ユーザーとコンパイラにとって有益です。まず、関数が例外をスローしないことがわかっていると、その関数を呼び出すコードが簡素化されます。第 2 に、関数が例外をスローしないことをコンパイラーが確認した場合、考えられるエラー コードには適用されない特別な最適化を実行できます。

       noexc キーワードを使用して関数が例外をスローしないように宣言されているにもかかわらず、実際には関数内で例外がスローされる場合があります。noexc 関数が例外をスローすると、プログラムは std::terminate() を呼び出してプログラムを終了し、実行時に例外をスローしないことを保証します。

       関数が例外をスローしないことを示します。そのため、呼び出し元は例外を処理する方法を考える必要がありません。関数が例外をスローしないか、例外をスローした後に強制終了されるかに関係なく、呼び出し元は例外を処理する方法を考える必要はありません。それに責任を持ちなさい。

       C++98 では、 throw() は例外がスローされないことを宣言するために使用され、 throw(例外タイプ) はスローされる可能性のある例外のタイプを宣言します。noexc は throw より効率的です。コンパイラは std::terminate() を使用してプログラムを終了でき、throw 例外メカニズムには関数スタックが順番に展開され、自動変数が破棄されるなど、追加のオーバーヘッドが発生するためです。

       プログラム プロセスのメモリが不十分な場合、新しい操作は bad_alloc 例外をスローし、メモリ割り当てに失敗します。この問題については以前に説明しました。解決策は、new 時に std::nothrow パラメータを渡し、new が実行できないようにすることです。メモリに適用する 例外をスローせず、直接 NULL を返します。返されたアドレスが NULL (空) かどうかでメモリ アプリケーションが失敗したかどうかを判断できるように、コードは次のとおりです。

#include <iostream>
 
int main(){
    char *p = NULL;
    int i = 0;
    do{
        p = new(std::nothrow) char[10*1024*1024]; // 每次申请10MB
        i++;
        
        Sleep(5);
    }
    while(p);
 
    if(NULL == p){
        std::cout << "分配了 " << (i-1)*10 << " M内存"         //分配了 1890 Mn内存第 1891 次内存分配失败           
                  << "第 " << i << " 次内存分配失败";
 
    }
    return 0;
}

もちろん、プログラムプロセスのメモリが不足すると業務が正常に起動・実行できなくなり、プログラムを生かしておく意味がありません。 

2.8、constexpr

       値が変化せず、コンパイル中に結果を取得できる式を指します。新しい C++11 標準では、変数が定数式であるかどうかをコンパイラが検証できるように、変数を constexpr 型として宣言できることが規定されています。constexpr として宣言された変数は定数である必要があり、定数式で初期化する必要があります。

constexpr int mf= 20;           // 20 是常量表达式
constexor int limit = mf + 1;   // mf + 1 是常量表达式
constexor int sz = size();         // 只有当size是一个constexpr函数时才是一条正确的语句

       constexpr は関数を変更することもできます。関数が constexpr として宣言されると、関数の戻り値の型とすべての仮パラメータの型はリテラル値型でなければならず、関数本体には retrun ステートメントを 1 つだけ含めることができます。

constexpr int new_sz(){ retrun 20; };

2.9、static_assert

       static_assert はコンパイル中にアサーションを作成するために使用されるため、静的アサーションと呼ばれます。構文は次のとおりです。

static_assert(定数式、プロンプト文字列)

例えば:

static_assert(sizeof(int) < sizeof(unsigned int), "int is not smaller than unsigned int");

最初のパラメーターの定数式の値が true (true またはゼロ以外の値) の場合、static_assert は存在​​しないかのように何もしません。それ以外の場合はコンパイル エラーが生成され、エラーの場所は static_assert が記述されている行になります。ステートメントが見つかりました。エラー プロンプトは 2 番目のパラメータのプロンプト文字列です。

       static_assert を使用すると、コンパイル中により多くのエラーを検出し、コンパイラとのいくつかの契約を強制し、コンパイル メッセージの読みやすさを向上させることができます。

おすすめ

転載: blog.csdn.net/chenlycly/article/details/132701306