ページ

2021年3月28日日曜日

定数参照したクラスインスタンスの関数呼び出し時に発生する警告は、constメンバー関数にすると消える


背景

cppで関数にクラスインスタンスを渡す際、「&」を付けて参照として渡すと実体をコピーしないため若干早くなります。
更に、constを付けて定数の参照と宣言すると、参照でありながら基本的に書き換えを許さないインスタンスになります。

参照で処理を高速化しながら安全に処理を書けて良いのですが、クラスの定義方法によっては関数呼び出し箇所で警告が発生しました。

警告は出るものの内部で値を書き換えない処理なら期待通りに動いてくれますが、警告が鬱陶しいので対応方法を調べて消しました。
備忘録を兼ねて対応方法と関連情報を記事として残します。

使ったもの

  • VSCode
    エディタです。
  • PlatformIO
    マイコン向けのプログラムをビルド出来る環境です。
    PlatformIOにプラグインをインストールすると、静的解析してエラーや警告を表示してくれます。
  • I2cControlPanel_asukiaaa
    今回変更するクラスを持つライブラリです。

警告が発生するコードの具体例

constと&を組み合わせ、infoを定数の参照の引数として扱っています。
void printInfo(const I2cControlPanel_asukiaaa::Info& info) {
Serial.print("leftOperatedDown" +
String(info.joyLeftOperatedDown()));
}

joyLeftOperatedDownを呼ぶ出す箇所で赤線が発生しました。


VSCode上で赤線にマウスカーソルを合わせると下記の警告が表示されます。
オブジェクトにメンバー 関数 "I2cControlPanel_asukiaaa::Info::joyLeftOperatedDown" と互換性のない型修飾子があります -- オブジェクト型は const I2cControlPanel_asukiaaa::Info ですC/C++(1086)

PlatformIOのビルドをすると、下記の警告が表示されます。
warning: passing 'const I2cControlPanel_asukiaaa::Info' as 'this' argument discards qualifiers [-fpermissive]
String(info.joyLeftOperatedDown()));

関数の宣言にconstを加え、constメンバー関数にすれば解決

const reference functionなどのキーワードで検索すると下記のページが見つかり、constメンバー関数の存在を知りました。
11.12 — Const class objects and member functions

具体的には引数を定義した閉じ括弧「)」の後にconstを記述します。

対応前
class Info {
bool joyLeftOperatedDown() { return joyLeftVert < ValueJoyLow; }
};

対応後
class Info {
bool joyLeftOperatedDown() const { return joyLeftVert < ValueJoyLow; }
};

クラスの定義と関数実装が別れている場合も同様に「)」の後にconstを追加すればconstメンバー関数になります。
class Info {
bool joyLeftOperatedDown() const;
};

bool Info::joyLeftOperatedDown() const { return joyLeftVert < ValueJoyLow; }

上記のようにクラスを変更すると警告が出なくなりました。


constメンバー関数とは?

警告を消してくれたconstメンバー関数は、内部ではthisをconstのポインタとして扱うようになる関数のようです。
そのため、constの参照で引数としてクラスインスタンスを扱った場合も、constの宣言が対応するため警告が出なくなるようです。

参考: 【C++】メンバ関数には必要に応じてconstをつけよう

まとめ

クラスで値を変更しない関数を定義する場合は、constを付けてconstメンバー関数とすると下記の利点があって良いです。
  • 関数内で値を書き換えないことを担保できる(ポインタは追えない)
  • 今回のようにクラスインスタンスをconstとして扱う場合に警告が出なくなる

今後値を返すだけのような関数は、なるべくconstメンバー関数として宣言しようと思いました。

0 件のコメント :

コメントを投稿