忍者ブログ
  • 2024.10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 2024.12
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

【2024/11/22 14:39 】 |
ラムダ式の中でthisが書き換わる
謎現象。
iOSでは起きないが、Androidで発生


[=](){
if (/*cond*/) {
var = captured_var;
func1();
}
func2();
}




こういうラムダ式があって、
func1を実行した後、func2の中で セグメンテーションフォルトで落ちた。

いろいろ調べてみると、thisの値がなぜか書き換わっていた。
func1()の中を処理している間は良いのだが、func1()からここに戻ってきた時に全然別の値になっている。
それでfunc2()を呼び出したもんだから何が起きるかわからない。

で、以下のようにthisを別の変数にもたせておけば、落ちずに進行した

[=](){
Klass* const instance = this;
if (/*cond*/) {
instance->var = captured_var;
instance->func1();
}
instance->func2();
}





しかしなぜthisが落ちるのか。
thisは暗黙的にコピーキャプチャーされている。
コピーキャプチャーされた変数は暗黙的にconstがついているはずだ。なぜなのか。

仮説
thisはちゃんとクラスインスタンスのことを表してるのか?
ラムダ式のインスタンス自身を表す変数もthisで、こちらと混同しているのか?(しかしラムダ式のthisを指定できる言語仕様なのか?そんなもの必要ない気がするし)







->解決
このラムダ式の中で、
ラムダ式自身を破棄していた。

そのため、関数を戻る時に、不定の位置に戻ってしまって(リターンコードが破棄されて別の値が書き込まれていた)
セグメンテーションフォルトになっていたのだった。
iOSでバグらなかったのは、そのメモリ位置がたまたま再利用されずそのまま残っていたからだろう

というわけで、ラムダ式は悪くない
PR
【2016/02/23 16:06 】 | C/C++ | 有り難いご意見(0)
インクリメントは前置のほうが速い
++i;
i++;

を比べると
++i;
のほうが速い。

違いはもちろん
前置インクリメントは、インクリメントを先に行う。
後置インクリメントは、インクリメントを後に行う。
ということだ。


前置の場合、自身のインスタンスをインクリメントし、自身を戻り値として返せば良い。
なぜなら、インクリメントが先だから。インクリメント後の値をその次の計算で使うので、インクリメントしたものをそのまま戻り値にすればよい。

後置の場合、そうはいかない。
インクリメントするが、戻り値として返すのはインクリメントする前の元の値である。
ということで、「インクリメントするまえに自身のコピーインスタンスを作成している」のだ。
そして、戻り値として返すのはこのコピーインスタンスなのである。

このコピーの手間分だけ、後置インクリメントは遅くなる。

クラスインスタンスなどはもとより、intなどのプリミティブ型でもその差は出てくる。


試しに以下の処理を実行してみる




その結果は以下のようになった。



何度もやると時間は変化するし、まれに逆転することもあるが、
後置は前置より遅くなる。
(この処理の前置と後置の順番を逆にしてもやはり後置が遅い)


というわけで、インクリメント処理は理由が無い限り前置を使うこと。
【2015/06/22 14:22 】 | C/C++ | 有り難いご意見(0)
クラス型の基本型へのキャスト
クラスの値を、基本型として解釈したいときは、
operator演算子で定義することができる。

class myClass{
operator bool() const{
return false;
}
operator int() const{
return 100;
}
operator float() const{
return 2.f;
}
};

myClass c;
int n = c; //n = 100
float f = c; //f = 2.f
bool b = c; //b = false


ただし、bool型の場合は特に注意。
間違った書き方をしてもコンパイルが通ってしまうことが起こりうる。
参照

【2011/06/26 06:05 】 | C/C++ | 有り難いご意見(0) | トラックバック()
数値のエスケープシーケンス
ヌル文字として

char c = '\0'

と書くことがよくある。

じゃあ、

c = '\1'

というのもあるのか。
もちろんある。
このときcの中身を16進数で表すと、0x01になっている。

'\1'があるのなら、'\2','\3','\4',,,,もずっとあるだろう。
否、そうではない。

'\8'

は無いのである。コンパイルエラーを起こす。
'\9'も無い。でも'\10'はある。
【2011/03/26 02:08 】 | C/C++ | 有り難いご意見(0) | トラックバック()
可変引数とPOD
可変引数には、POD型の変数しか渡せない。
ワーニングが表示され、そのまま実行すると実行時エラーが発生してしまう。
va_arg()の第2引数もPOD型しか使えない。

○可変引数
myPrintf( const char*, ...);
の「...」の部分。

○POD型
Plain Old Dataの略。
バイト列だけで表現できる変数型のこと。
int, floatなどのプリミティブ型や、
以下の条件を満たす構造体(struct, class, union)もPODに含まれる。
--
ユーザが定義するコンストラクタを持たない
ユーザが定義するデストラクタを持たない
ユーザが定義するコピーコンストラクタを持たない
仮想関数を持たない
基底クラスを持たない
private または protected のnon-staticメンバ変数を持たない
参照であるnon-staticメンバ変数を持たない
--
生成や代入がデフォルトの通りだとか、
つまり、何も考えずにプリミティブと同じように使える構造体ならPOD、ということ。


参考ページ
http://www.game-create.com/archives/302

【2011/01/28 01:20 】 | C/C++ | 有り難いご意見(0) | トラックバック()
| ホーム |