Top | Wiki | Blog | Github  

C++ Tips

C++のメモです.

const を使う

#include <iostream>
using namespace std;
 
static int funct_B(int* a){
  cout << a[0] <<endl;
}
 
static int funct_A(const int* a){
  cout << a[0] << endl;
  funct_B(a); // NG
  funct_B(const_cast<int*>(a)); //OK
}
 
int main(){
 
  int a[5];
  for(int i=0; i<5; i++){
    a[i] = i;
  }
  funct_A(a);
 
  return 1;
}

このサンプルコードで保護されるのは,ポインタの指し示すデータ,つまり配列の中身である.ポインタを保護したい場合には,アスタリスクの右側に const を配置すればよい.

int const *a // データが保護される
int* const a // アドレスが保護される
const int* const a // アドレスもデータも保護される int const * const a でも意味は一緒.重要なのは const の右側に何があるか.

ところが,2次元配列の場合は少し勝手が違う.なぜなら,配列の中身がポインタのためである.

int const **a // NG
int* const *a // アドレスが保護される a[0] = 0; // NG
int** const a // アドレスが保護される a = 0; // NG
 
int const * const *a // データが保護される

どうやら,データが保護されるためにはそれを指し示しているアドレスも保護されていることが前提のようである.関数で2次元配列のポインタを受け取り,データを保護しながら使いたい場合には,const*const *a となっておればよい.

  • const オブジェクトは,非 const メンバ関数を呼び出せない
class A{
private:
    int a;
public:
    A():a(10){};
    ~A(){};
    void show(){ std::cout << a << std::endl; };
};
 
void showNum(const A& val){
    val.show();
}
 
int main(){
    A a;
    showNum(a);
 
    return 1;
}

このコードは,コンパイルエラーとなる.

error: the object has cv-qualifiers that are not compatible with the member function

正しくは,

class A{
private:
    int a;
public:
    A():a(10){};
    ~A(){};
    void show() const { std::cout << a << std::endl; }; // メンバ変数を変更しないことが明らかな,constメンバ関数とする.
};
 
void showNum(const A& val){
    val.show();
}
 
int main(){
    A a;
    showNum(a);
 
    return 1;
}

show() を const メンバ関数と定義したので,const 参照とした val から show() を呼び出すことができる.

クラス設計後,このクラスを const 参照で呼び出した人が困らないように,メンバ変数を変更しないことが明らかなメンバ変数は,const メンバ関数としておけばよい.

ld が文句を言うとき

スタティックライブラリを利用する場合,リンク時に直接 XXX.a を指定すればOK.

一方ダイナミックリンクを指定するときは,-lXXX とする.これは,所定の場所に,libXXX.so なるファイルが存在していることが前提となっている.-lXXX と指定しても ld が文句を言う場合は,locate コマンドで libXXX を探し,libXXX.so が存在しているかを調べる.libXXX.so.3 などとなっていたら,ln -s libXXX.so.3 libXXX.so としてシンボリックリンクを作成してあげればよい.