アプリケーション開発ポータルサイト
ServerNote.NET
カテゴリー【C/C++
【C++】shared_ptrで生成したクラス配列を複数の優先順位でソートする
POSTED BY
2023-12-16

普通に複数のメンバ変数・メンバ関数を持つオリジナルクラスを、std::shared_ptrでメモリ確保・初期化し、std::vector配列に格納するまでは一般的だが、それを好きな条件でその場でソートする例が意外に見つからなかったのでメモ。

C++11以降であればインラインで比較関数記述ができるラムダ式std::sortが使える。

以下の例は、時間のメンバ変数mJikan、距離のメンバ変数mDistanceと、それを出力する関数dumpを持つオリジナルクラスAを定義し、shared_ptrでこのクラスを5個生成し、順不同なmJikan、mDistanceのままvectorにまず格納している。

そしてstd::sortの第3引数に比較関数を定義する。第3引数は以下のような形式を取る。

[](auto const& c1, auto const& c2) {
//ここに比較条件を記述し、
//入れ替えるならtrue、入れ替えないならfalseをreturnする
});

auto const& c1,c2はそれぞれvectorに格納されている比較すべき2つのオブジェクト=格納したのはポインタshared_ptrなのでクラスAへのsharedポインタ=である。

つまりc1ー>mJikanなどと、自身のメンバ変数や関数、さらにクラス外のstd::関数やstaticクラスのメンバ関数なども好きに呼べるので複雑な比較条件のもと真ならtrueを返せばvector内の順番は入れ替わる。

ここでポイントとなるのは複数のメンバ変数を優先順位で比較したい場合。その場合はstd::tieで優先したいメンバ変数を順に列挙することで実現する。以下、最後の例がそれである。

C/C++shared_vector_sort.cppGitHub Source
#include <iostream>
#include <algorithm>
#include <vector>
#include <memory>
#include <tuple>

class A {
public:
  int mJikan;
  int mDistance;

  A(int jikan, int distance) {
    mJikan = jikan;
    mDistance = distance;
  }

  ~A(void) {

  }

  void dump(void) {
    std::cout << "mJikan=" << mJikan << ", mDistance=" << mDistance << std::endl;
  }
};

int main(void) {

  std::shared_ptr<A> a1 = std::make_shared<A>(10, 2);
  std::shared_ptr<A> a2 = std::make_shared<A>(4, 0);
  std::shared_ptr<A> a3 = std::make_shared<A>(7, 6);
  std::shared_ptr<A> a4 = std::make_shared<A>(7, 3);
  std::shared_ptr<A> a5 = std::make_shared<A>(6, 1);

  std::vector<std::shared_ptr<A>> va = std::vector<std::shared_ptr<A>>();
  va.push_back(a1);
  va.push_back(a2);
  va.push_back(a3);
  va.push_back(a4);
  va.push_back(a5);

  //mJikanの昇順でソートする場合

  std::sort(va.begin(), va.end(), [](auto const& c1, auto const& c2) {
    return c1->mJikan < c2->mJikan;
  });

  std::cout << "Sorted by A->mJikan" << std::endl;

  std::for_each(va.begin(), va.end(), [](auto const& c) {
    c->dump();
  });

  //mDistanceの昇順でソートする場合

  std::sort(va.begin(), va.end(), [](auto const& c1, auto const& c2) {
    return c1->mDistance < c2->mDistance;
  });

  std::cout << "Sorted by A->mDistance" << std::endl;

  std::for_each(va.begin(), va.end(), [](auto const& c) {
    c->dump();
  });

  //mJikanの昇順でソートし、mJikanが同一ならmDistanceの昇順でソートする場合

  std::sort(va.begin(), va.end(), [](auto const& c1, auto const& c2) {
    return std::tie(c1->mJikan, c1->mDistance) < std::tie(c2->mJikan, c2->mDistance);
  });

  std::cout << "Sorted by A->mJikan AND A->mDistance" << std::endl;

  std::for_each(va.begin(), va.end(), [](auto const& c) {
    c->dump();
  });

  return 0;
}

コンパイル、実行結果

g++ shared_vector_sort.cpp

./a.out

Sorted by A->mJikan
mJikan=4, mDistance=0
mJikan=6, mDistance=1
mJikan=7, mDistance=6
mJikan=7, mDistance=3
mJikan=10, mDistance=2

Sorted by A->mDistance
mJikan=4, mDistance=0
mJikan=6, mDistance=1
mJikan=10, mDistance=2
mJikan=7, mDistance=3
mJikan=7, mDistance=6

Sorted by A->mJikan AND A->mDistance
mJikan=4, mDistance=0
mJikan=6, mDistance=1
mJikan=7, mDistance=3
mJikan=7, mDistance=6
mJikan=10, mDistance=2

最後の例は、「mJikanが同一ならmDistanceの昇順」とstd::tieで指定しているので、最初の例と比較して、mDistance=3, 6がしっかり入れ替わっていることが確認できる。

※本記事は当サイト管理人の個人的な備忘録です。本記事の参照又は付随ソースコード利用後にいかなる損害が発生しても当サイト及び管理人は一切責任を負いません。
※本記事内容の無断転載を禁じます。
【WEBMASTER/管理人】
自営業プログラマーです。お仕事ください!
ご連絡は以下アドレスまでお願いします★

【キーワード検索】