C++のmaxについて

AI実装検定のご案内

C++のmaxは、複数の値を比較して、その中から最大値を取得するために使われる機能です。

一般的には、標準ライブラリのstd::maxを使用します。

std::maxは整数や小数だけでなく、文字列や独自クラスなど、大小関係を比較できる型にも利用できます。

基本的には<algorithm>ヘッダーをインクルードして使用します。

#include <algorithm>
#include <iostream>

int main() {
    int a = 10;
    int b = 20;

    std::cout << std::max(a, b) << '\n';
}

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

20

1020を比較し、大きい20が返されています。

目次

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

2つの値から最大値を取得する

std::maxの基本構文は次のとおりです。

std::max(a, b)

2つの値を比較し、大きいほうを返します。

#include <algorithm>
#include <iostream>

int main() {
    int x = 30;
    int y = 15;

    int result = std::max(x, y);

    std::cout << result << '\n';
}

実行結果は次のようになります。

30

整数を比較する

std::maxは整数の最大値を求める場合によく利用されます。

int a = 100;
int b = 200;

int maximum = std::max(a, b);

この場合、maximumには200が代入されます。

負の整数でも問題なく利用できます。

int a = -10;
int b = -5;

std::cout << std::max(a, b);

結果は-5です。

doubleやfloatを比較する

std::maxはテンプレート関数なので、intだけでなくdoublefloatにも利用できます。

double a = 3.14;
double b = 2.71;

std::cout << std::max(a, b);

結果は3.14です。

floatでも同じように使えます。

float x = 1.5f;
float y = 2.5f;

float result = std::max(x, y);

この場合、result2.5fになります。

3つ以上の値から最大値を求める方法

std::maxを入れ子にする

3つの値から最大値を求める場合は、std::maxを入れ子にできます。

int a = 10;
int b = 30;
int c = 20;

int result = std::max(a, std::max(b, c));

結果は30です。

まずbcを比較し、その結果をaと比較しています。

初期化リストを利用する

C++11以降では、初期化リストを使って複数の値をまとめて比較できます。

#include <algorithm>
#include <iostream>

int main() {
    int result = std::max({10, 30, 20, 50, 40});

    std::cout << result << '\n';
}

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

50

固定された複数の値から最大値を取得する場合は、入れ子にするより読みやすくなることがあります。

なお、初期化リスト版のstd::maxでは、少なくとも1つの要素を指定する必要があります。

std::maxの戻り値

2引数版はconst参照を返す

2引数版のstd::maxは、大きいほうの値へのconst参照を返します。

概念的には次のような関数です。

template<class T>
const T& max(const T& a, const T& b);

通常は次のように値として受け取れば問題ありません。

int result = std::max(a, b);

ただし、戻り値を参照として保持する場合には、引数の寿命に注意する必要があります。

2つの値が同じ場合

2引数版のstd::maxでは、2つの値が等価な場合、第1引数が選択されます。

int a = 10;
int b = 10;

const int& result = std::max(a, b);

値だけを見るとどちらも10ですが、参照として見るとaが選ばれています。

std::stringでmaxを使う方法

文字列も比較できる

std::maxは数値専用ではありません。

比較可能な型であれば利用できます。

たとえばstd::stringも比較できます。

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

int main() {
    std::string a = "apple";
    std::string b = "banana";

    std::cout << std::max(a, b) << '\n';
}

結果は次のようになります。

banana

文字列は辞書式に比較されます。

そのため、文字数が多いほうが必ず大きくなるわけではありません。

std::string a = "z";
std::string b = "apple";

この場合は"z"のほうが大きいと判定されます。

charでmaxを使う方法

文字同士も比較できる

char同士にもstd::maxを利用できます。

char a = 'A';
char b = 'Z';

std::cout << std::max(a, b);

結果は次のとおりです。

Z

char同士では、それぞれの文字を表す値に基づいて大小が比較されます。

特定の文字コード体系だけを前提にした機能ではない点には注意が必要です。

異なる型をstd::maxに渡す際の注意点

intとdoubleはそのまま比較できない

次のように異なる型を直接渡すと、一般的な2引数版std::maxではコンパイルエラーになります。

int a = 10;
double b = 20.5;

auto result = std::max(a, b);

std::maxでは基本的に、2つの引数から同じテンプレート型Tを決定する必要があるためです。

型をそろえて比較する

安全で分かりやすい方法は、型を明示的にそろえることです。

auto result = std::max(static_cast<double>(a), b);

また、次のようにテンプレート引数を指定することもできます。

auto result = std::max<double>(a, b);

ただし、2引数版std::maxは参照を返すため、型変換によって生成された一時オブジェクトを戻り値として参照保持するコードには注意が必要です。

通常は、戻り値をautoなどで値として受け取るか、あらかじめ引数の型をそろえてから比較すると安全です。

配列の最大値を求める方法

std::max_elementを使用する

配列全体から最大値を探す場合は、通常std::maxではなくstd::max_elementを使用します。

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

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

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

    std::cout << *it << '\n';
}

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

80

std::max_elementは最大値そのものではなく、最大要素を指すイテレータを返します。

そのため、値を取得するときは*itのように逆参照します。

vectorの最大値を求める方法

vectorでもstd::max_elementを使う

std::vectorから最大値を探す場合にもstd::max_elementが便利です。

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

int main() {
    std::vector<int> numbers = {5, 12, 3, 100, 42};

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

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

結果は次のとおりです。

100

空のvectorに対してstd::max_elementを実行すると、end()が返されます。

そのため、逆参照する前に次のような確認を行うと安全です。

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

std::maxとstd::max_elementの違い

std::maxは値同士を比較する

std::maxは、主に2つの値や初期化リスト内の値を比較するときに使用します。

std::max(10, 20);

または、

std::max({10, 20, 30});

のように使います。

std::max_elementは範囲から最大要素を探す

std::max_elementは、配列やvectorなどの範囲から最大要素を探すためのアルゴリズムです。

std::max_element(v.begin(), v.end());

使い分けを整理すると、次のようになります。

用途使用する機能
2つの値を比較するstd::max
固定された複数の値を比較するstd::max({...})
配列から最大要素を探すstd::max_element
vectorから最大要素を探すstd::max_element

比較方法を指定してstd::maxを使う方法

比較関数を渡せる

std::maxには、比較関数を指定できるオーバーロードがあります。

std::max(a, b, comp)

たとえば絶対値が大きいほうを選びたい場合は、ラムダ式を利用できます。

#include <algorithm>
#include <cmath>
#include <iostream>

int main() {
    int a = -100;
    int b = 50;

    auto result = std::max(a, b, [](int x, int y) {
        return std::abs(x) < std::abs(y);
    });

    std::cout << result << '\n';
}

結果は次のとおりです。

-100

絶対値では10050なので、-100が選択されます。

比較関数comp(a, b)は、指定した比較規則においてabより小さい場合にtrueを返すように定義します。

独自クラスでstd::maxを使う方法

比較可能なクラスなら利用できる

独自クラスでも、適切な比較方法が定義されていればstd::maxを利用できます。

#include <algorithm>
#include <iostream>

class Score {
public:
    int value;

    explicit Score(int v) : value(v) {}

    bool operator<(const Score& other) const {
        return value < other.value;
    }
};

int main() {
    Score a(80);
    Score b(95);

    const Score& result = std::max(a, b);

    std::cout << result.value << '\n';
}

結果は次のとおりです。

95

独自型でも、どちらが小さいかを適切に判定できればstd::maxを利用できます。

std::minとの違い

std::maxは最大値、std::minは最小値を返す

std::maxと対になる関数がstd::minです。

int a = 10;
int b = 20;

std::cout << std::max(a, b) << '\n';
std::cout << std::min(a, b) << '\n';

実行結果は次のようになります。

20
10

std::maxは大きい値、std::minは小さい値を返します。

最小値と最大値を同時に取得する方法

std::minmaxを使用する

最小値と最大値の両方が必要な場合は、std::minmaxを利用できます。

#include <algorithm>
#include <iostream>

int main() {
    int a = 30;
    int b = 10;

    auto result = std::minmax(a, b);

    std::cout << "min: " << result.first << '\n';
    std::cout << "max: " << result.second << '\n';
}

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

min: 10
max: 30

配列やvectorなどの範囲について最小要素と最大要素を同時に探したい場合は、std::minmax_elementも利用できます。

std::ranges::maxの使い方

C++20以降ではRanges版も利用できる

C++20以降では、std::ranges::maxを利用できます。

#include <algorithm>
#include <iostream>

int main() {
    int a = 10;
    int b = 30;

    std::cout << std::ranges::max(a, b) << '\n';
}

結果は次のとおりです。

30

std::ranges::maxでは、範囲そのものを渡して最大値を取得することもできます。

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

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

    int maximum = std::ranges::max(numbers);

    std::cout << maximum << '\n';
}

結果は30です。

範囲から最大要素の位置を取得したい場合は、std::ranges::max_elementを利用できます。

std::numeric_limits::max()との違い

std::maxは値同士を比較する

std::maxは、実際の値同士を比較して大きいほうを取得するための機能です。

std::max(10, 20);

この場合は20が返されます。

numeric_limitsのmaxは型の最大有限値を取得する

std::numeric_limits<T>::max()は、指定した型で表現できる最大の有限値を取得するための機能です。

#include <iostream>
#include <limits>

int main() {
    std::cout << std::numeric_limits<int>::max() << '\n';
}

一般的な32ビットintの環境では、次の値になります。

2147483647

ただし、C++規格ではintが必ず32ビットであるとは限りません。

そのため、型の最大値をコード内で固定値として書くよりも、std::numeric_limits<T>::max()を利用するほうが適切です。

numeric_limitsのminとの違いに注意する

numeric_limitsを使う場合は、min()の意味にも注意が必要です。

整数型では、

std::numeric_limits<int>::min()

は最小値を取得します。

一方、浮動小数点型の、

std::numeric_limits<double>::min()

は通常、最も小さい正の正規化された有限値を意味します。

最も負側の有限値を取得したい場合は、

std::numeric_limits<double>::lowest()

を利用します。

std::maxを使うメリット

コードを簡潔に書ける

最大値は条件演算子でも取得できます。

int result = (a > b) ? a : b;

しかし、std::maxを使えば次のように簡潔に書けます。

int result = std::max(a, b);

関数名だけで「最大値を取得する処理」であることが分かるため、可読性も高くなります。

さまざまな型に利用できる

std::maxはテンプレートとして提供されているため、整数だけでなく、浮動小数点数や文字列、独自型などにも利用できます。

汎用性が高く、C++プログラムでは頻繁に使われる標準ライブラリ機能の一つです。

std::maxを使う際の注意点

std::を付けて使用する

標準ライブラリのmaxを利用する場合は、基本的に次のように書くことをおすすめします。

std::max(a, b)

using namespace std;を使用すると、

max(a, b)

とも書けますが、名前の衝突が発生する可能性があります。

特に規模の大きいプログラムやヘッダーファイルでは、std::maxと明示したほうが安全です。

引数の型をそろえる

次のように異なる型をそのまま渡すと、コンパイルできない場合があります。

std::max(10, 20.5);

次のように型をそろえると安全です。

std::max(10.0, 20.5);

Windows環境ではmaxマクロとの衝突に注意する

一部のWindows向けヘッダーでは、maxという名前のマクロが定義され、std::maxと衝突するケースがあります。

必要に応じて、Windowsヘッダーをインクルードする前にNOMINMAXを定義します。

#define NOMINMAX
#include <Windows.h>

#include <algorithm>

これはC++標準ライブラリそのものの問題ではなく、Windows向けヘッダーとの名前衝突によって発生する問題です。

C++のmaxについてのまとめ

C++で最大値を取得するときに最も基本となるのがstd::maxです。

2つの値を比較する場合は、次のように書きます。

std::max(a, b)

複数の固定値から最大値を取得する場合は、初期化リストを利用できます。

std::max({a, b, c})

配列やvectorなどの範囲から最大要素を探す場合は、std::max_elementを使用します。

std::max_element(v.begin(), v.end())

C++20以降では、std::ranges::maxstd::ranges::max_elementも利用できます。

また、型そのものが表現できる最大有限値を取得したい場合は、std::maxではなく次の機能を使用します。

std::numeric_limits<T>::max()

このように、C++では目的に応じてstd::maxstd::max_elementstd::ranges::maxstd::numeric_limits<T>::max()を使い分けることが重要です。

以上、C++のmaxについてでした。

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

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