yet another

#include <cstdio>
struct I {
    virtual I *f() = 0;
};
struct A : virtual I {
    virtual I *f() { puts("A"); return this; }
};
struct B : virtual I {
    virtual I *f() { puts("B"); return this; }
    B(I *x) { x->f(); }
};
struct C : A, B {
    virtual I *f() { puts("C"); return this; }
    C() : A(), B(((A *)this)->f()) { ((A *)this)->f(); }
};
int main() {
    C c;
}

何が出るかな、何が(ry

続きを読む

ぷらすぷらす

id:succeed:20080623 に関して。

C だと後置増分演算子の意味規則は次のように規定されている [6.5.2.4]。

後置++演算子の結果は、そのオペランドの値とする。結果を取り出した後、オペランドの値を増分する(すなわち、適切な型の値 1 をそれに加える。)。...

なんだか二度読み出すのが正統のような気すらするんだけど、どうなんでしょうか。

C++ でも似たような感じ [5.2.6]。

後置演算子 ++ を作用させて得る値は、演算子を作用させる前の演算対象の値とする。... 結果を得た後で、そのオブジェクトの値は、1 が加算された値に変更する。...

曖昧だが、原文も“After the result is noted, the value of the object is modified by adding 1 to it”らしい。

ついでに Java だとこう [15.4.2]。

... the value 1 is added to the value of the variable and the sum is stored back into the variable. ... The value of the postfix increment expression is the value of the variable before the new value is stored. ...

素直に受け取ると二度は読まない…のか? むぅ、読解に自信がない。

共有メモリ

クラスタとかならともかく、単なるデュアルコア程度ではこういう現象は起こらないと何となく思っていた。

$ cat Test.java
public class Test {
    public static void main(String[] args) {
        for (;;)
            test();
    }
    static int a, b, x, y;
    static void test() {
        try {
            a = b = 1;
            Thread t1 = new Thread() {
                public void run() { a = 2; x = b; }
            };
            Thread t2 = new Thread() {
                public void run() { b = 2; y = a; }
            };
            t1.start(); t2.start();
            t1.join(); t2.join();
            if (x == 1 && y == 1)
                System.exit(0);
        } catch (InterruptedException e) {
        }
    }
}
$ javac Test.java
$ time java Test
     4070.06 real      1584.35 user      3679.72 sys

この発生率のバグに出くわしたら泣ける。