C++のstd::findについて

AI実装検定のご案内

std::findは、指定した範囲の中から、特定の値と等しい要素を検索するC++標準ライブラリの関数です。

配列やstd::vectorstd::liststd::dequestd::stringなど、イテレータで範囲を表現できるデータに対して使用できます。

std::findを使用するには、次のヘッダをインクルードします。

#include <algorithm>

基本的な書き方は次のとおりです。

std::find(検索開始位置, 検索終了位置, 検索する値);

std::findの戻り値は、見つかった要素を指すイテレータです。

値が見つからなかった場合は、検索範囲の終了位置として指定したイテレータが返されます。

目次

std::findの基本構文

実行ポリシーを使用しない基本的な形式は、概念的には次のようになります。

template<class InputIt, class T>
constexpr InputIt find(
    InputIt first,
    InputIt last,
    const T& value
);

C++のバージョンによって、厳密な関数宣言や型のデフォルト指定などは異なりますが、基本的な使い方は同じです。

各引数の意味

引数内容
first検索を開始する位置
last検索範囲の終了位置
value検索したい値

検索範囲は、次のような半開区間で表されます。

[first, last)

これは、firstが指す要素は検索対象に含まれますが、lastが指す位置は含まれないことを意味します。

たとえば、次のコードでは、numbers.begin()からnumbers.end()の直前までが検索対象です。

std::find(
    numbers.begin(),
    numbers.end(),
    30
);

end()は最後の要素そのものではなく、最後の要素の次の位置を表します。

std::findの基本的な使い方

std::vectorから値を検索する例

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 40, 50
    };

    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        30
    );

    if (it != numbers.end()) {
        std::cout
            << "値が見つかりました: "
            << *it
            << '\n';
    } else {
        std::cout
            << "値は見つかりませんでした\n";
    }

    return 0;
}

実行結果は次のとおりです。

値が見つかりました: 30

std::findの戻り値はイテレータなので、見つかった値を取得するにはデリファレンスします。

*it

ただし、値が見つからなかった場合、itnumbers.end()になります。

そのため、必ずend()と異なることを確認してからデリファレンスする必要があります。

if (it != numbers.end()) {
    std::cout << *it << '\n';
}

値が見つからなかった場合

検索対象の値が存在しない場合、std::findは第2引数に指定した終了イテレータを返します。

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    100
);

if (it == numbers.end()) {
    std::cout
        << "見つかりませんでした\n";
}

検索に指定した終了位置と比較する

検索結果は、必ず検索時に第2引数として渡した終了イテレータと比較します。

コンテナ全体を検索した場合は、通常、次のように書きます。

if (it != numbers.end()) {
}

一部分だけを検索した場合は、その部分の終了位置と比較します。

auto last = numbers.begin() + 3;

auto it = std::find(
    numbers.begin(),
    last,
    30
);

if (it != last) {
    std::cout
        << "見つかりました\n";
}

見つかった要素の位置を取得する方法

std::findはインデックスではなく、イテレータを返します。

先頭から何要素進んだ位置にあるかを取得したい場合は、std::distanceを使用できます。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 40, 50
    };

    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        40
    );

    if (it != numbers.end()) {
        auto position = std::distance(
            numbers.begin(),
            it
        );

        std::cout
            << "位置: "
            << position
            << '\n';
    }

    return 0;
}

実行結果は次のとおりです。

位置: 3

std::vectorでは、この値をインデックスとして扱えます。

10 → 0
20 → 1
30 → 2
40 → 3
50 → 4

std::distanceの計算量

std::distanceの計算量は、イテレータの種類によって異なります。

std::vectorstd::arrayのようなランダムアクセスイテレータでは、通常は定数時間です。

O(1)

一方、std::liststd::forward_listでは、先頭から対象位置まで順番に進むため、線形時間になる可能性があります。

O(N)

また、std::listには配列のような添字アクセスがないため、厳密には「インデックス」ではなく「先頭からの距離」と考えるのが適切です。

イテレータ同士を引き算する方法

std::vectorstd::arrayでは、次のようにイテレータ同士を引き算できます。

auto index = it - numbers.begin();

ただし、この方法はstd::listなどでは使用できません。

コンテナを問わず使いやすい方法は、std::distanceです。

配列でstd::findを使用する方法

C形式の配列

C形式の配列にもstd::findを使用できます。

#include <algorithm>
#include <iostream>
#include <iterator>

int main()
{
    int numbers[] = {
        10, 20, 30, 40, 50
    };

    auto it = std::find(
        std::begin(numbers),
        std::end(numbers),
        30
    );

    if (it != std::end(numbers)) {
        std::cout
            << "見つかりました: "
            << *it
            << '\n';
    }

    return 0;
}

std::beginstd::endを使うと、配列の先頭と末尾を安全に取得できます。

ポインタを直接使用することもできます。

int numbers[] = {
    10, 20, 30, 40, 50
};

auto it = std::find(
    numbers,
    numbers + 5,
    30
);

ただし、要素数を手動で指定する必要があるため、通常はstd::beginstd::endのほうが分かりやすいでしょう。

std::array

#include <algorithm>
#include <array>
#include <iostream>

int main()
{
    std::array<int, 5> numbers = {
        10, 20, 30, 40, 50
    };

    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        20
    );

    if (it != numbers.end()) {
        std::cout
            << "見つかりました\n";
    }

    return 0;
}

文字列を検索する方法

vector内の文字列を検索する

std::vector<std::string>の中から、特定の文字列を検索することもできます。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> fruits = {
        "apple",
        "banana",
        "orange"
    };

    auto it = std::find(
        fruits.begin(),
        fruits.end(),
        "banana"
    );

    if (it != fruits.end()) {
        std::cout
            << "見つかりました: "
            << *it
            << '\n';
    }

    return 0;
}

この場合、各要素と検索値が等しいかどうかが比較されます。

要素型と検索値の型が完全に同じでなくても、両者を比較できれば検索可能です。

たとえば、上のコードでは、std::stringの要素と文字列リテラルを比較しています。

部分一致ではなく完全一致

std::findは、文字列の部分一致検索を行う関数ではありません。

たとえば、次の検索では"banana"の中に"nan"が含まれていても見つかりません。

auto it = std::find(
    fruits.begin(),
    fruits.end(),
    "nan"
);

std::findは、各要素全体が検索値と等しいかを調べます。

std::stringの中から1文字を検索する方法

std::stringもイテレータを持つため、文字列内から特定の文字を検索できます。

#include <algorithm>
#include <iostream>
#include <string>

int main()
{
    std::string text = "Hello";

    auto it = std::find(
        text.begin(),
        text.end(),
        'l'
    );

    if (it != text.end()) {
        std::cout
            << "文字が見つかりました: "
            << *it
            << '\n';
    }

    return 0;
}

"Hello"には'l'が2つありますが、std::findが返すのは最初に見つかった要素です。

std::string::findとの違い

文字列内の文字や部分文字列を検索する場合は、std::string::findというメンバ関数もあります。

std::size_t position = text.find("ll");

std::findstd::string::findは、名前が似ていますが別の機能です。

項目std::findstd::string::find
種類標準アルゴリズムstd::stringのメンバ関数
主な用途範囲内の要素検索文字・部分文字列の検索
戻り値イテレータ位置を表す整数型
見つからない場合laststd::string::npos

std::findは最初に一致した要素を返す

同じ値が複数存在する場合でも、std::findが返すのは最初に一致した要素です。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 20, 40
    };

    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        20
    );

    if (it != numbers.end()) {
        std::cout
            << std::distance(
                numbers.begin(),
                it
            )
            << '\n';
    }

    return 0;
}

実行結果は次のとおりです。

1

2つ目の20ではなく、最初の20の位置が返されます。

すべての一致要素を検索する方法

std::findを繰り返し使用すると、同じ値を持つすべての要素を検索できます。

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 20, 40, 20
    };

    auto it = numbers.begin();

    while (
        (it = std::find(
            it,
            numbers.end(),
            20
        )) != numbers.end()
    ) {
        std::cout
            << "位置: "
            << std::distance(
                numbers.begin(),
                it
            )
            << '\n';

        ++it;
    }

    return 0;
}

実行結果は次のとおりです。

位置: 1
位置: 3
位置: 5

一致した要素の次から検索を再開するために、次の処理が必要です。

++it;

これを省略すると、同じ要素が繰り返し見つかり、無限ループになる可能性があります。

一致する要素数だけを知りたい場合

一致する要素の個数だけを調べたい場合は、std::countのほうが適しています。

auto count = std::count(
    numbers.begin(),
    numbers.end(),
    20
);

検索範囲を限定する方法

std::findでは、コンテナ全体ではなく一部分だけを検索できます。

std::vector<int> numbers = {
    10, 20, 30, 40, 50
};

auto first = numbers.begin() + 1;
auto last = numbers.begin() + 4;

auto it = std::find(
    first,
    last,
    30
);

この場合、検索対象は次の3要素です。

20, 30, 40

範囲は[first, last)なので、lastが指す50は含まれません。

検索結果は、検索に使用したlastと比較します。

if (it != last) {
    std::cout
        << "見つかりました\n";
}

独自クラスをstd::findで検索する方法

std::findで独自型を検索するには、範囲内の要素と検索値を等価比較できる必要があります。

一般的には、operator==を定義します。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

struct User
{
    int id;
    std::string name;

    bool operator==(const User& other) const
    {
        return id == other.id
            && name == other.name;
    }
};

int main()
{
    std::vector<User> users = {
        {1, "Alice"},
        {2, "Bob"},
        {3, "Carol"}
    };

    User target{
        2,
        "Bob"
    };

    auto it = std::find(
        users.begin(),
        users.end(),
        target
    );

    if (it != users.end()) {
        std::cout
            << "見つかりました: "
            << it->name
            << '\n';
    }

    return 0;
}

operator==はメンバ関数でなくてもよい

operator==は、必ずしもクラスのメンバ関数として定義する必要はありません。

非メンバ関数として定義することもできます。

struct User
{
    int id;
    std::string name;
};

bool operator==(
    const User& lhs,
    const User& rhs
)
{
    return lhs.id == rhs.id
        && lhs.name == rhs.name;
}

C++20以降では、デフォルト比較も利用できます。

struct User
{
    int id;
    std::string name;

    bool operator==(
        const User&
    ) const = default;
};

重要なのは、コンテナの要素と検索値を比較できることです。

イテレータからメンバにアクセスする方法

イテレータがクラスオブジェクトを指している場合、メンバには->でアクセスできます。

it->name

これは、次の書き方と同じ意味です。

(*it).name

特定のメンバだけを条件に検索する方法

std::findは、基本的に要素全体と検索値を比較します。

たとえば、Userオブジェクトの中から「IDが2のユーザー」を探したい場合は、通常、std::find_ifを使用します。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

struct User
{
    int id;
    std::string name;
};

int main()
{
    std::vector<User> users = {
        {1, "Alice"},
        {2, "Bob"},
        {3, "Carol"}
    };

    auto it = std::find_if(
        users.begin(),
        users.end(),
        [](const User& user) {
            return user.id == 2;
        }
    );

    if (it != users.end()) {
        std::cout
            << "見つかりました: "
            << it->name
            << '\n';
    }

    return 0;
}

std::findとstd::find_ifの違い

std::find

std::findは、指定した値と等しい要素を検索します。

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    30
);

概念的には、次のような比較が行われます。

*it == 30

std::find_if

std::find_ifは、指定した条件を満たす最初の要素を検索します。

auto it = std::find_if(
    numbers.begin(),
    numbers.end(),
    [](int value) {
        return value >= 30;
    }
);

この場合、30以上の最初の要素が見つかります。

std::find_if_not

std::find_if_notは、指定した条件を満たさない最初の要素を検索します。

auto it = std::find_if_not(
    numbers.begin(),
    numbers.end(),
    [](int value) {
        return value < 30;
    }
);

この例では、「30未満ではない最初の値」、つまり30以上の最初の値を検索します。

C++20のstd::ranges::find

C++20以降では、std::ranges::findも使用できます。

従来のstd::findでは、開始位置と終了位置をそれぞれ指定します。

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    30
);

std::ranges::findでは、範囲を直接渡せます。

#include <algorithm>
#include <iostream>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 40
    };

    auto it = std::ranges::find(
        numbers,
        30
    );

    if (it != numbers.end()) {
        std::cout
            << "見つかりました\n";
    }

    return 0;
}

begin()end()を個別に書く必要がないため、コードが簡潔になります。

std::ranges::findのプロジェクション

std::ranges::findでは、プロジェクションを利用して、構造体の特定のメンバを直接検索できます。

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

struct User
{
    int id;
    std::string name;
};

int main()
{
    std::vector<User> users = {
        {1, "Alice"},
        {2, "Bob"},
        {3, "Carol"}
    };

    auto it = std::ranges::find(
        users,
        2,
        &User::id
    );

    if (it != users.end()) {
        std::cout
            << it->name
            << '\n';
    }

    return 0;
}

次のコードは、各Userオブジェクトのidを取り出し、値2と比較するという意味です。

std::ranges::find(
    users,
    2,
    &User::id
);

従来のstd::find_ifで書くと、次のようになります。

auto it = std::find_if(
    users.begin(),
    users.end(),
    [](const User& user) {
        return user.id == 2;
    }
);

単純なメンバ検索では、std::ranges::findのプロジェクションを使うと簡潔に書けます。

std::ranges::findで一時オブジェクトを渡す場合の注意点

std::ranges::findに名前を持つコンテナを渡す場合は、通常のイテレータが返されます。

std::vector<int> numbers = {
    10, 20, 30
};

auto it = std::ranges::find(
    numbers,
    20
);

一方、一時的なコンテナを直接渡す場合は注意が必要です。

auto result = std::ranges::find(
    std::vector<int>{
        10, 20, 30
    },
    20
);

一時的なstd::vectorは式の終了時に破棄されるため、その要素を指すイテレータを安全に返せません。

このような場合、戻り値がstd::ranges::danglingになることがあります。

初心者のうちは、検索結果を後で使用する場合、名前を付けたコンテナに対してstd::ranges::findを使うと安全です。

std::findの計算量

std::findは、検索範囲の先頭から順番に要素を比較します。

要素数をNとした場合、最悪計算量は次のとおりです。

O(N)

対象の値が先頭にあれば、比較は1回で済みます。

一方、対象が最後にある場合や、値が存在しない場合は、最大で範囲内のすべての要素を確認します。

{10, 20, 30, 40, 50}

この中から50を探す場合は、概念的に次のように比較します。

10 == 50
20 == 50
30 == 50
40 == 50
50 == 50

ソート済みの配列やstd::vectorから高速に検索したい場合は、std::binary_searchstd::lower_boundも選択肢になります。

ただし、これらを使用するには、基本的に対象範囲が適切にソートされている必要があります。

std::findが使用できるコンテナ

std::findは、入力イテレータとして扱える範囲であれば使用できます。

代表的なコンテナは次のとおりです。

std::vector
std::array
std::deque
std::list
std::forward_list
std::string

setやmapではメンバ関数のfindを使う

std::setstd::mapには、コンテナ自身のfindメンバ関数があります。

std::set<int> values = {
    10, 20, 30
};

auto it = values.find(20);

std::setに対してstd::findを使うことも可能です。

std::find(
    values.begin(),
    values.end(),
    20
);

しかし、std::findは先頭から順番に調べるため、計算量は線形時間です。

O(N)

一方、std::set::findは、通常、対数時間で検索できます。

O(log N)

そのため、連想コンテナでは、基本的にコンテナ自身のfindを使用します。

unordered_setやunordered_mapの場合

std::unordered_set::findstd::unordered_map::findの計算量は、平均的には定数時間です。

平均 O(1)

ただし、ハッシュ衝突が集中した場合など、最悪では線形時間になる可能性があります。

最悪 O(N)

std::mapで値を検索する場合の注意点

std::map::findは、マップされた値ではなくキーを検索します。

#include <iostream>
#include <map>
#include <string>

int main()
{
    std::map<int, std::string> users = {
        {1, "Alice"},
        {2, "Bob"},
        {3, "Carol"}
    };

    auto it = users.find(2);

    if (it != users.end()) {
        std::cout
            << it->second
            << '\n';
    }

    return 0;
}

std::mapの要素はキーと値のペアです。

it->first

it->firstはキーを表します。

it->second

it->secondはマップされた値を表します。

値側を条件に検索する方法

値側から検索したい場合は、std::find_ifを使用します。

auto it = std::find_if(
    users.begin(),
    users.end(),
    [](const auto& entry) {
        return entry.second == "Bob";
    }
);

よくある間違い

戻り値をそのままboolとして扱う

次のような書き方はできません。

if (
    std::find(
        numbers.begin(),
        numbers.end(),
        30
    )
) {
}

std::findの戻り値はboolではなくイテレータです。

正しくは、終了イテレータと比較します。

if (
    std::find(
        numbers.begin(),
        numbers.end(),
        30
    ) != numbers.end()
) {
    std::cout
        << "存在します\n";
}

C++17の初期化文付きifを使う

検索結果のイテレータを後続処理で使う場合は、C++17以降の初期化文付きifも便利です。

if (
    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        30
    );
    it != numbers.end()
) {
    std::cout
        << *it
        << '\n';
}

見つからない場合にデリファレンスする

次のコードは危険です。

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    100
);

std::cout << *it;

値が見つからなかった場合、itnumbers.end()になります。

end()をデリファレンスすると未定義動作になります。

正しくは、先に検索結果を確認します。

if (it != numbers.end()) {
    std::cout
        << *it
        << '\n';
}

別のコンテナのend()と比較する

イテレータは、検索対象と同じコンテナの終了イテレータと比較する必要があります。

std::vector<int> a = {
    1, 2, 3
};

std::vector<int> b = {
    4, 5, 6
};

auto it = std::find(
    a.begin(),
    a.end(),
    2
);

次の比較は誤りです。

if (it != b.end()) {
}

正しくは、検索対象であるaの終了イテレータと比較します。

if (it != a.end()) {
}

コンテナ変更後もイテレータを使う

コンテナに要素を追加または削除すると、取得済みのイテレータが無効になることがあります。

std::vector<int> numbers = {
    10, 20, 30
};

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    20
);

numbers.push_back(40);

std::vector::push_backによって容量の再確保が発生すると、既存のすべてのイテレータが無効になります。

再確保が発生しない場合でも、以前のend()イテレータは無効になります。

コンテナを変更した後は、必要に応じて検索し直すのが安全です。

部分一致ができると思ってしまう

次の検索は、文字列の完全一致です。

std::vector<std::string> words = {
    "apple",
    "pineapple",
    "orange"
};

auto it = std::find(
    words.begin(),
    words.end(),
    "apple"
);

この検索では、"apple"という要素には一致しますが、"pineapple"を部分一致として返しません。

部分文字列を含む要素を探す場合は、std::find_ifを使用します。

auto it = std::find_if(
    words.begin(),
    words.end(),
    [](const std::string& word) {
        return word.find("apple")
            != std::string::npos;
    }
);

要素が存在するかだけを確認する方法

値や位置が不要で、存在するかどうかだけを確認したい場合は、次のように書けます。

bool exists =
    std::find(
        numbers.begin(),
        numbers.end(),
        30
    ) != numbers.end();

使用例は次のとおりです。

if (exists) {
    std::cout
        << "30が存在します\n";
}

C++20では、std::ranges::findを使うこともできます。

bool exists =
    std::ranges::find(
        numbers,
        30
    ) != numbers.end();

C++23のstd::ranges::contains

C++23以降では、要素の存在確認にstd::ranges::containsを使用できます。

#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30
    };

    if (
        std::ranges::contains(
            numbers,
            20
        )
    ) {
    }

    return 0;
}

std::ranges::containsは、イテレータを返すのではなく、要素が存在するかどうかをboolで返します。

検索結果の位置や要素そのものが不要な場合に適しています。

コンテナのcontainsメンバ関数との違い

std::setstd::mapなどの連想コンテナには、C++20からcontainsメンバ関数があります。

std::set<int> numbers = {
    10, 20, 30
};

if (numbers.contains(20)) {
}

一方、std::vectorにはcontainsメンバ関数はありません。

C++23以降では、std::ranges::containsを使用できます。

std::ranges::contains(
    numbers,
    20
);

要素を検索して削除する方法

最初に見つかった要素だけを削除する

最初に見つかった要素を1つだけ削除する場合は、std::finderaseを組み合わせます。

#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30, 20, 40
    };

    auto it = std::find(
        numbers.begin(),
        numbers.end(),
        20
    );

    if (it != numbers.end()) {
        numbers.erase(it);
    }

    return 0;
}

処理後の内容は次のようになります。

10, 30, 20, 40

最初の20だけが削除されます。

すべての一致要素を削除する

すべての20を削除したい場合は、std::removeeraseを組み合わせます。

numbers.erase(
    std::remove(
        numbers.begin(),
        numbers.end(),
        20
    ),
    numbers.end()
);

この書き方は、erase-removeイディオムと呼ばれます。

C++20以降であれば、std::eraseを使用できます。

std::erase(
    numbers,
    20
);

constなコンテナで使用する場合

constなコンテナに対してもstd::findを使用できます。

const std::vector<int> numbers = {
    10, 20, 30
};

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    20
);

この場合、返されるイテレータは、要素を変更できないイテレータとして扱われます。

そのため、検索結果を通して値を書き換えることはできません。

*it = 100;

このコードはコンパイルエラーになります。

変更可能なコンテナの場合は、取得したイテレータを通して値を書き換えられます。

std::vector<int> numbers = {
    10, 20, 30
};

auto it = std::find(
    numbers.begin(),
    numbers.end(),
    20
);

if (it != numbers.end()) {
    *it = 200;
}

処理後の内容は次のようになります。

10, 200, 30

存在確認処理を関数化する方法

値が存在するかどうかを確認する処理を、テンプレート関数にまとめることもできます。

#include <algorithm>

template<class Container, class T>
bool contains(
    const Container& container,
    const T& value
)
{
    return std::find(
        container.begin(),
        container.end(),
        value
    ) != container.end();
}

使用例は次のとおりです。

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> numbers = {
        10, 20, 30
    };

    if (contains(numbers, 20)) {
        std::cout
            << "存在します\n";
    }

    return 0;
}

ただし、C++23以降であれば、同様の用途にstd::ranges::containsを使用できます。

std::findの実装イメージ

std::findの基本的な動作は、概念的には次のようなコードで表せます。

template<class InputIt, class T>
constexpr InputIt my_find(
    InputIt first,
    InputIt last,
    const T& value
)
{
    while (first != last) {
        if (*first == value) {
            return first;
        }

        ++first;
    }

    return last;
}

処理の流れは次のとおりです。

  1. firstlastに到達していないか確認する
  2. 現在の要素と検索値を比較する
  3. 一致した場合は現在のイテレータを返す
  4. 一致しなければ次の要素へ進む
  5. 最後まで見つからなければlastを返す

ただし、実際の標準ライブラリ内部では、処理が最適化されている場合があります。

このコードは、あくまで動作を理解するための概念的な実装です。

std::findの要点まとめ

std::findは、指定した範囲の中から、検索値と等しい最初の要素を探す関数です。

基本的な書き方は次のとおりです。

auto it = std::find(
    container.begin(),
    container.end(),
    value
);

検索結果は、検索に指定した終了イテレータと比較します。

if (it != container.end()) {
}

重要なポイントは次のとおりです。

  • 戻り値はboolではなくイテレータ
  • 見つからない場合は第2引数の終了イテレータを返す
  • 検索範囲は半開区間[first, last)
  • 複数の一致がある場合は最初の要素を返す
  • 検索結果をデリファレンスする前に、見つかったか確認する
  • 独自型では検索値との等価比較が可能である必要がある
  • 任意の条件で検索する場合はstd::find_ifを使う
  • C++20以降ではstd::ranges::findも利用できる
  • C++23以降では存在確認にstd::ranges::containsを利用できる
  • 計算量は基本的にO(N)
  • std::setstd::mapでは、通常、コンテナ自身のfindを使う
  • std::unordered_setstd::unordered_mapの検索は平均O(1)、最悪O(N)
  • コンテナ変更後はイテレータが無効になる可能性がある

最も基本的で安全な使用例は、次のコードです。

auto it = std::find(
    values.begin(),
    values.end(),
    target
);

if (it != values.end()) {
    std::cout
        << "見つかりました: "
        << *it
        << '\n';
} else {
    std::cout
        << "見つかりませんでした\n";
}

以上、C++のstd::findについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次