【C++】モダンC++の機能を解説

モダンC++画像 C++基礎

この記事では、モダンC++の主要な機能の自動型推論(auto)、スマートポインタ(std::unique_ptr, std::shared_ptr)、ラムダ式、範囲ベースのforループ、constexprを解説します。これらの機能は、コードの可読性と効率を向上させ、より安全で簡潔なプログラミングスタイルを可能にします。

これらの機能を理解し、適切に使用することで、あなたのC++コードはより効率的で、保守性が高く、エラーが少なくなります。

プログラムを実行するための環境構築がまだの方は「C++を実行するための環境構築|初心者でも簡単!(Windows)」をご覧ください。

自動型推論(auto)

autoキーワードは、変数の型を自動的に推論します。これは、型名が長すぎるか、明示的な型名が不要な場合に便利です。

#include <iostream>

int main() {
    auto num = 5;  // int型として推論されます
    auto str = "Hello, World!";  // const char*型として推論されます

    std::cout << num << "\n";
    std::cout << str << "\n";

    return 0;
}

実行結果

5
Hello, World!

このコードでは、autoキーワードを使用してnumstrの型を自動的に推論しています。numは整数値を持つため、int型として推論され、strは文字列リテラルを持つため、const char*型として推論されます。

autoは型推論を容易にしますが、型が明確でない場合は使用を避け、型を明示的に指定することをお勧めします。

スマートポインタ(std::unique_ptr, std::shared_ptr)

std::unique_ptrの基本的な使用方法

std::unique_ptrは、所有権を1つのポインタに制限するスマートポインタです。これにより、メモリリークを防ぎ、リソースの自動的な解放を保証します。

#include <iostream>  // 入出力操作に必要なライブラリをインクルード
#include <memory>    // スマートポインタに必要なライブラリをインクルード

int main() {
    std::unique_ptr<int> ptr(new int(10));  // ヒープ上に新しいintを作成し、そのアドレスをスマートポインタで管理

    std::cout << *ptr << "\n";  // スマートポインタが指す値を出力

    return 0;  // プログラムが正常に終了したことをOSに伝える
}

実行結果

10

このコードでは、std::unique_ptrを使用して動的に割り当てられた整数の所有権を管理しています。ptrがスコープを抜けるとき、自動的に割り当てられたメモリが解放されます。

std::unique_ptrはリソースの所有権を明確にするため、リソースリークを防ぐのに役立ちます。ただし、所有権を複数のポインタ間で共有する必要がある場合は、std::shared_ptrを使用することを検討してください。

std::shared_ptrの基本的な使用方法

std::shared_ptrは、複数のポインタ間で所有権を共有するスマートポインタです。これにより、メモリリークを防ぎ、リソースの自動的な解放を保証します。

#include <iostream>  // 入出力操作に必要なライブラリをインクルード
#include <memory>    // スマートポインタに必要なライブラリをインクルード

int main() {
    std::shared_ptr<int> ptr1(new int(10));  // ヒープ上に新しいintを作成し、そのアドレスをスマートポインタで管理
    std::shared_ptr<int> ptr2 = ptr1;  // ptr1が指すメモリの所有権を共有

    std::cout << *ptr1 << "\n";  // ptr1が指す値を出力
    std::cout << *ptr2 << "\n";  // ptr2が指す値を出力(ptr1とptr2は同じメモリを指しているので、出力は同じになります)

    return 0;  // プログラムが正常に終了したことをOSに伝える
}

実行結果

10
10

このコードでは、std::shared_ptrを使用して動的に割り当てられた整数の所有権を管理しています。ptr1ptr2は同じリソースの所有権を共有しています。どちらかがスコープを抜けるとき、他方がまだ存在していればリソースは解放されません。両方がスコープを抜けたときに初めてリソースが解放されます。

std::shared_ptrはリソースの所有権を複数のポインタ間で共有するため、リソースリークを防ぐのに役立ちます。ただし、所有権を1つのポインタに制限する必要がある場合は、std::unique_ptrを使用することを検討してください。また、所有権の共有はコストがかかるため、必要な場合にのみ使用してください。

ラムダ式

ラムダ式は、無名関数または匿名関数とも呼ばれ、一時的な使用や短い関数を定義するのに便利です。

#include <iostream>  // 入出力ストリームライブラリをインクルード
#include <vector>    // ベクター(動的配列)ライブラリをインクルード
#include <algorithm> // アルゴリズムライブラリをインクルード(for_each関数を使用するため)

int main() {
    // 整数のベクターを作成し、初期値を設定
    std::vector<int> numbers = { 1, 2, 3, 4, 5 };

    // ベクター内の各要素に対してラムダ関数を適用
    std::for_each(numbers.begin(), numbers.end(), [](int num) {
        // 各要素を標準出力に表示
        std::cout << num << "\n";
        });

    // プログラムの終了を示す
    return 0;
}

実行結果

1
2
3
4
5

このコードは、ベクターに格納された整数をイテレートし、各整数をラムダ関数を使って標準出力に表示します。std::for_eachを使用して、ベクターの各要素に対して指定された操作(この場合は数値の出力)を実行します。

std::for_each(numbers.begin(), numbers.end(), [](int num) { ... });:ベクター内の各要素に対してラムダ関数を適用します。

  • numbers.begin():ベクターの最初の要素を指すイテレータを取得します。
  • numbers.end():ベクターの最後の要素の次を指すイテレータを取得します。
  • [](int num) { ... }:ラムダ関数を定義します。この場合、引数として整数numを受け取り、その値を出力します。

ラムダ式はコードを簡潔にし、ローカルスコープでのみ必要な関数を定義するのに役立ちます。ただし、複雑なロジックは通常の関数または関数オブジェクトに分割することを検討してください。

範囲ベースのforループ

範囲ベースのforループは、コンテナのすべての要素を簡単に反復処理するための機能です。

#include <iostream>  // 入出力ストリームライブラリをインクルード
#include <vector>    // ベクター(動的配列)ライブラリをインクルード

int main() {
    // 整数のベクターを作成し、初期値を設定
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    // ベクター内の各要素をループで繰り返し処理
    for (const auto& num : numbers) {
        // 各要素を標準出力に表示
        std::cout << num << "\n";
    }

    // プログラムの終了を示す
    return 0;
}

実行結果

1
2
3
4
5

このコードでは、範囲ベースのforループを使用してベクトルのすべての要素を出力しています。

for (const auto& num : numbers) { ... }:範囲ベースのforループを使用して、ベクター内の各要素を繰り返し処理します。

  • const auto& num:各要素を定数参照として受け取ります。この方法は、要素をコピーせずに効率的にアクセスできます。
  • : numbers:ループがベクターnumbersの各要素を順に処理することを示します。

範囲ベースのforループはコードを簡潔にし、コンテナのすべての要素を簡単に反復処理できます。ただし、特定の範囲の要素のみを反復処理する場合や、反復の順序を制御する必要がある場合は、通常のforループを使用することを検討してください。

constexpr

constexprはC++11で導入されたキーワードで、コンパイル時に定数として評価される式を指定するために使用されます。関数や変数に適用することができ、コンパイル時に計算を行うことで実行時のパフォーマンスを向上させることができます。

#include <iostream>

// constexprを使ってコンパイル時に計算される関数を定義
constexpr int add(int a, int b) {
    return a + b;
}

int main() {
    // コンパイル時に計算される定数
    constexpr int result = add(2, 3);

    std::cout << "2 + 3 = " << result << "\n"; // 2 + 3 = 5 と出力される
    return 0;
}

実行結果

2 + 3 = 5
  • この例では、add関数がconstexprとして定義されています。
  • add(2, 3)はコンパイル時に計算され、resultに格納されます。
  • 実行時には計算が行われず、すぐに結果が出力されます。

constexprはパフォーマンスを向上させ、コンパイル時にエラーを検出するのに役立ちます。ただし、すべての関数がconstexprに適しているわけではありません。関数がコンパイル時に評価可能で、その結果が定数であることが必要な場合にのみ使用してください。

まとめ

  • 自動型推論(auto):型名が長すぎるか、明示的な型名が不要な場合に便利です。
  • スマートポインタ(std::unique_ptr, std::shared_ptr):メモリリークを防ぎ、リソースの自動的な解放を保証します。
  • ラムダ式:一時的な使用や短い関数を定義するのに便利です。
  • 範囲ベースのforループ:コンテナのすべての要素を簡単に反復処理するための機能です。
  • constexpr:コンパイル時に評価される定数表現を指定します。これにより、パフォーマンスが向上し、コンパイル時にエラーを検出できます。

モダンC++の機能は、コードの可読性と効率を向上させ、より安全で簡潔なプログラミングスタイルを可能にします。これらの機能を理解し、適切に使用することで、あなたのC++コードはより効率的で、保守性が高く、エラーが少なくなります。

モダンC++の機能を活用し、より効率的で保守性の高いコードを書きましょう!

次のページ >> 【C++】入出力とファイル操作を解説

【C++】をより詳しく学びたい方はこちら >>【C++】入門書おすすめ3選!超初心者~中級者まで網羅!

プログラムを実行するための環境構築がまだの方は「C++を実行するための環境構築|初心者でも簡単!(Windows)」をご覧ください。

コメント

タイトルとURLをコピーしました