C++でIPアドレスをソートする

さっと検索した範囲だとサンプルが見つからず、単純だけど自分で作ったのでメモ。例によって力技。数値変換せずに文字列比較だけ(ユニコード前提)。

データは、他の自サイトに最近1ヵ月ほどでアクセスのあったGooglebotやGoogleの他サービスのIPアドレス。(ちなみにいずれも全リストが公開されている。Googlebot / 他サービス使用IP。参照した記事はこちら )

比較関数

まず比較関数を用意する。とりあえず、よく使うstd::wstring版。(不正な文字列とかの対策は足りないかも)

(降順ソートは比較を逆にするだけ。)

テストコード

出力結果

64.233.172.180
66.102.8.152
66.102.8.158
66.249.64.152
66.249.66.86
66.249.68.1
66.249.68.5
66.249.68.6
66.249.68.9
66.249.68.13
66.249.68.17
66.249.68.20
66.249.68.21
66.249.68.24
66.249.68.25
66.249.68.28
66.249.68.30
66.249.72.239
66.249.72.241
66.249.72.243
66.249.74.16
66.249.79.20
66.249.79.133
66.249.79.135
66.249.79.137
66.249.79.139
66.249.79.141
66.249.79.143
66.249.79.145
66.249.79.147
66.249.79.153
66.249.82.16
66.249.82.18
66.249.82.20
66.249.82.26
66.249.82.28
66.249.82.30
66.249.82.176
66.249.82.178
66.249.82.180
66.249.82.186
66.249.82.188
66.249.82.190
66.249.83.17
66.249.83.19
66.249.83.21
66.249.88.40
66.249.88.42
66.249.88.44
66.249.88.45
66.249.88.46
66.249.88.47
72.14.199.68
72.14.199.70
72.14.199.72
72.14.199.73
72.14.199.76
72.14.199.77
72.14.199.79
72.14.199.80
72.14.201.152
72.14.201.153
74.125.150.1
74.125.150.19
74.125.150.20
74.125.150.23
74.125.150.24
74.125.150.25
74.125.150.27
74.125.150.28
74.125.150.31
74.125.212.235
74.125.212.237
74.125.212.239
74.125.212.241
74.125.212.243
74.125.214.16
74.125.214.18
74.125.214.20
74.125.214.26
107.178.234.23
107.178.234.85
107.178.234.88
107.178.234.92
107.178.234.144
107.178.234.147
107.178.234.155
107.178.234.156
107.178.234.158
130.211.54.158
193.186.4.134
193.186.4.152
193.186.4.153

汎用版

これだけだと芸がないので、stringとかu16stringとか一通りの文字列型に対応する汎用版。
関数テンプレートの特殊化ってこういう使い方でいいのかよく分かってないが。
区切り文字の取得以外は、前のコードとほぼ同じ。

呼び出しはこんな感じ。

区切りの文字定数取得は、c++14以降だとbasic_string_viewを使ってもう少しすっきり出来るらしい。

C++Builder10.2.3 / Windows10(22H2)で確認。

vectorの重複要素をソートせずに削除する[c++]

vectorの重複要素の削除は、まずソートしてから std::unique / erase という定番手法があるが、現在の要素の順番を崩さないまま行いたい場合もある。

こうしたケース用に、何か定番の方法があるのかと調べたら、こちらのサイトを見ただけでも実にいろいろなやり方があるらしい。

とりあえず、要素の大きさとか重複率とか気にせず、速度や効率にこだわらなければ、結局 std::set を使うベタな方法が個人的には一番分かりやすかった。

なおstd::setのメンバ関数countは1か0を返すだけ。std::findを使うよりシンプルに書ける。

テンプレート関数を作っておくと、どんな型を突っ込んだvectorでもだいたい使えるので楽かもしれない。(というか自分用に作った)

ついでに std::remove_if と c++11以降のラムダ式も使ったバージョン。std::deque版。

これは、setのinsert関数の返値を使うともっとシンプルに書ける、とこちらのサイトで知った。

setのメンバ関数 insert は、引数1つのバージョンだと std::pair<iterator,bool>を返す。挿入に成功するとsecondにはtrueが入る。なるほど便利。

   
C++Builder10.2.3で確認。

[c++]vectorを配列に/配列をvectorに

どっちからどっちに変換するかで方法が違うため、すぐ忘れるのでメモ。

vectorから配列

std::copyを使う方法。

配列からvector

std::copyやvectorのメンバ関数assignを使う方法もあるが、c++11以降なら、以下がたぶん一番シンプル。

配列の大きさとか

以下、おまけ。
既存のvectorに配列を代入するなど、配列のサイズ(要素数)を知りたい場合、c++11以降だと、sizeofを利用する以外の方法も用意されている。

ただし、既存のvectorに、異なるサイズの配列を代入するだけなら、メモリや実行速度にシビアでなければ、いちいちサイズを求めなくとも以下で済むといえば済む。

[c++11]本日の経過ミリ秒を取得する

現在、本日が始まってから何ミリ秒過ぎたかを求めるため、c++11で追加されたstd::chronoライブラリを勉強がてら使ってみた。もっとスマートな方法もあるかもしれないが。以下、c++11/Windows環境の場合。c++17やLinux環境だと別の方法もあるらしい。

現在時刻に関する情報はnow()関数で取れる。なおこの時刻はUTC(協定世界時)であり日本時間とは異なる。

time_since_epoc関数で「エポックからの経過時間」を求めて、メンバ関数countでミリ秒を取得。そこから現在時刻のミリ秒部分を得る。この「エポック」が何時なのかは未規定だが概ね1970/1/1で、経過ミリ秒は軽く1兆を超える値になり、32bit intでは正常に収容できないので注意が必要。(もちろんautoを使えば問題ない)。

時間・分・秒を取得するため、time_tに変換。さらに現地時間(日本時間)に変換する。

この時点で本日の経過ミリ秒は自前で計算可能だが、せっかくtime_pointは減算が効くので、本日0時0分0秒000のtime_stampを求めてみる。

time_point同士の減算から本日の経過ミリ秒を求める。

以下、まとめてシンプルに。

月初めからや年頭からの経過ミリ秒も求めたいが、std::chrono::monthやstd::chrono::yearはc++20で追加予定らしいので、c++11だとすんなりとはいかないようだ。
c++20では、ローカル時間用のtime_pointとか、 1日内の時間情報を取得するクラスtime_of_dayなども追加されるらしく、time_t変換などせずに、もっと楽に取得できるようになるかも。

c++builder10.2.3/Windows10(64bit/1909)で確認。

vectorの要素をloopしながら削除(添え字版)

久しぶりにやるといつも忘れて、Web検索するハメになるけれど、イテレータの使用例ばかり出てくる(気がする)ので、添え字版をメモ。

std::dequeでも同様。

std::accumulateとtemplate

一度どハマりしたことがあるのでメモ。
std::accumulateは、vectorなどコンテナの要素を加算してくれる便利な関数だが、第三引数にちょっと罠がある。
まず特に問題ないサンプル。

出力結果 : sum : 6

ところが以下の例だと値が丸められてしまう。

出力結果 : sum : 6

この場合は、第三引数がdoubleでなくてはならない。

出力結果 : sum : 6.6

テンプレートクラス内などで使う場合はstatic_castを使う。
例えばメンバをvectorで保持するクラスに合計値を出す関数を実装する例。

出力してみる。

出力結果:
sum : 6
sum : 6.6

続・Compositeパターンをshared_ptrで実装する…Clone/Assignの追加

Compositeパターンをshared_ptrで実装するの続き。

DeepCopyを作る”Clone”メソッドや、他のComponentから内容をコピーする”Assign”メソッドもあると便利。

Compositeもメンバ変数を保持することも想定して実装してみる。
もっとスマートなやり方もありそうだが、とりあえず、Compositeとその子クラスに非公開のデフォルトコンストラクタを実装する方式で。
(前回同様、c++11の機能を使っているが、c++11以前でもboost利用で同様の実装が可能。また行数省略のためすべてheaderに実装している。)

1.Componentクラス
Clone/Assign用の純粋仮想関数を追加する。

2.Compositeクラス
Clone/Assignメソッドを実装する。
Compositeの派生クラス用の純粋仮想関数doClone/doAssignも追加。
デフォルトConstructorはprotectedとする。
メンバ変数”name_”も追加、

3.ConcreteCompositeクラス
doClone/doAssignメソッドを実装する。非公開のコンストラクタも追加。
doCloneは非公開のデフォルトコンストラクタで作成したshared_ptrを返すだけ。

(不正なAssignの対応は何もしていないが、本来は例外を投げるなどのエラー処理が必要かも)

4.テストコード
適当に親子関係を作成した後、CloneとAssignを実行する。

実行結果
————————
name:c1/A: val == 3
 name:c2/B: str == child
  name:c3/B: str == child of child
   name:c4/A: val == 107
 name:c5/B: str == other child
–Clone–
name:c1/A: val == 3
 name:c2/B: str == child
  name:c3/B: str == child of child
   name:c4/A: val == 107
 name:c5/B: str == other child
–Before Assign–
name:assigned_compo/A: val == 0
–After Assign–
name:c1/A: val == 3
 name:c2/B: str == child
  name:c3/B: str == child of child
   name:c4/A: val == 107
 name:c5/B: str == other child
————————

ConcreteCompositeのメンバを追加・変更した場合、doAssignメソッドのみを書き換えればOK。

Compositeパターンをshared_ptrで実装する

かつて情報をネットで探したときに、断片的な情報はあるものの、分かりやすいサンプルが見付からなかったのでメモ。
Compositeパターンをshared_ptrで実装するのは、単にポインタをshared_ptrに置き換えるだけだと、循環参照が発生する。

ポイントは2つ。
 1.親(Parent)のポインタはshared_ptrでなくweak_ptrに置き換える
 2.shared_from_thisを使う

以下のコードはc++11以降のstl版だが、c++11以前でもboostで同様の実装が可能。必要なヘッダをincludeすれば”std::”を”boost::”に置き換えるだけでOK。
(説明を短くするために全てheaderに入れている)

まずComponentクラス。
メンバ”parent_”をweak_ptrで保持する。

(Executeは階層構造を出力するだけのテスト用Method)

つづいてCompositeクラス。
継承元に”std::enable_shared_from_this”を指定するのがポイント。
また”Add”で親をセットする際、”shared_from_this()”を使う。


CompositeのConcreteクラスを2つ作ってみる。ひとつはstd::string, もう一つはintをメンバに持つことにする。

実行してみる。適当に親子関係を作り、出力。

出力結果。
—————————————-
A: val == 3
 B: str == child
  B: str == child of child
   A: val == 107
 B: str == other child
—————————————-

生ポインタを使うのと比べ、解放処理が不要で便利。