さようならロボット - こんにちはマラスムス - ページ 7

 
Renat:
...

この例のテスト。

  • MQL4/MQL5 - 潜在的なエラーについて警告を表示します。

  • Visual Studio 2012、コード解析を含む - 何もない、潜在的なエラーの解析の質はゼロです。昔からライバルがいないので、気にしないのでしょう。

  • PVS Studio - 正しくレポートします。

  • Lint - 同じことを報告しますが、'x'が隠れる...

    ...

パブリック

メッセージも絶対に無駄だと思います。私はプロのプログラマーではありませんが、µlのこのような無意味なことはストレスになります。aとbへの参照が一定である場合、PVS Studioは警告を発生させるのでしょうか(自分で確認する方法がない)。

それでも、まず警告の要旨に触れてから、議論として持ち出すのは悪いことではありません。PVS Studioが警告を出すのは、グローバル変数が 隠されているからではなく、aやbが定数でない参照で渡されているが、変更されていないからです。その場合、aやbは定数参照で渡すべきだと考えている。例えば、次のような例では、このアナライザーは文句を言いません。

int a=1,b=2;
int sum(const int& a, const int& b){
        return(a+b);
}

int main(){
        return sum(a,b);
}

//-------------------------------------------------
int a=1,b=2;
int sum(int& a, int& b){
        ++a; ++b;
        return(a+b);
}

int main(){
        return sum(a,b);
}
 

PVSが何を責めているのか、よく分かっています。

もう一度言いますが、私たちには何十億行もの古いC/C++のコードをコンパイルする責任という重荷はないのです。警告を発生させて彼らのビジネスを台無しにしないのは、彼ら自身のコンパイラー次第である。一方、私たちは、お金を扱うアプリケーション言語のセキュリティとエラーコントロールに責任を負っています。

MQL4/5のコード作成者のうち、プロの(本当の意味での)プログラマーは数パーセントに過ぎません。あとは独学で、どれだけひどいコードを書いているのかわからない人ばかりです。

例えば、アップデートされたMQL4に移行した後、コドベースの何千ものソースを手作業で調べ、彼らの古いコードにある信じられないほどの数のエラーを修正しなければならなかったのです。プログラムを実行しなくても、コンパイラによって多くのエラーが発見され、表示されるようになりました。

だからこそ、警告を出すという主張ではなく、自分たちでコードを修正することが必要なのです。

 
Renat:

PVSが何を責めているのか、よく分かっています。

もう一度言いますが、私たちには何十億行もの古いC/C++のコードをコンパイルする責任という重荷はないのです。警告を発生させて彼らのビジネスを台無しにしないのは、彼ら自身のコンパイラー次第である。一方、私たちは、お金を扱うアプリケーション言語のセキュリティとエラーコントロールに責任を負っています。

MQL4/5のコード作成者のうち、プロの(本当の意味での)プログラマーは数パーセントに過ぎません。あとは独学で、どれだけひどいコードを書いているのかわからない人ばかりです。

例えば、アップデートされたMQL4に移行した後、コドベースの何千ものソースを手作業で調べ、彼らの古いコードにある信じられないほどの数のエラーを修正しなければならなかったのです。プログラムを実行しなくても、コンパイラによって多くのエラーが発見され、表示されるようになりました。

だからこそ、警告を出すことに文句を言わず、コードを修正すべきなのです。


配列で範囲を外せるのであれば、インジケータ自体を書くときに、計算開始の計算だけで、インジケータを書くときと同等の労力をかけるのは非常に愚かなことです。

このコードを掘り下げる必要はない、半分は修正されていない、壊れているのだ。古いmql4、新しいmql4、新しいmql4 with strictを区別するプロパティを追加で作ればよかったのでは?旧コンパイラーではどのようなサイズになるのでしょうか?わからないが、おそらく1メガバイト以下だろう。ギガバイトの時代に持ち歩いても問題ない。しかし、ここではコードベースの破壊という、一種の英雄的行為が行われている。

* * *

警告

a' の宣言が X 行目のグローバル宣言を隠している。

これはバカみたいな警告だ。上の世界の誰かが問題を起こしても、他の人がそのような問題を起こす可能性があるとは限りません。変数にはスコープが あり、誰かが変数と呼ぶものはプライベートな問題です。

 
Integer:


もし、配列がその範囲をすり抜けてしまうようなことがあれば、インジケータを書くときに、インジケータそのものを書くのと同等の努力をするのは非常に愚かで、計算の起点だけを計算することになります。

このコードを掘り下げることは避けられたはずです。半分は修正されておらず、壊れています。旧mql4、新mql4、新with strictを区別するための追加プロパティを作ればよかったのでは?旧コンパイラーではどのようなサイズになるのでしょうか?わからないが、おそらく1メガバイト以下だろう。ギガバイトの時代に持ち歩いても問題ない。しかし、ここで一種の英雄的な仕事が行われた--コードベースを破壊することだ。

まさにfixed、brokenではありません。

もし、編集後に誤りがあったのなら、その可能性は十分にあります。しかし、だからといってシングルエラーを旗に掲げて、修正したものを山ほど登ればいいというものでもないでしょう。


a'はX行目のグローバル宣言を隠蔽しています。

これはバカみたいな警告だ。もし、「上」の世界の誰かが問題を抱えていたとしても、他の人がそのような問題を抱えているとは限りません。変数が見える領域がある、誰が何を変数と呼ぶかは私事です。

自己撮影の権利のために戦う、驚くべき人々。特に、「古いコンパイラは放っておけ」と大真面目に書いてくれる人はありがたいですね。
 
simpleton:

潜在的なエラーは、必ずしも全くエラーでないため、潜在的なエラーであると言えます。

どうだろう、どうだろう。以前は、リリース時にレベル4や5のワラントを入れて、ワラントをエラーとしてカウントするボックスにチェックを入れるという経験則があったのですが、今はどうでしょうか。

本当にくだらない警告はプラグマで解消したんですけどね。

 
Andrei01:

この発言は無意味であり、主張されているように変数 "a "の隠蔽がないため、原則的にプログラマーに有益な情報を提供しない。

1.cpp(3): remark #3280: declaration hides variable "a" (declared at line 1)
  int sum(int& a, int& b){        

もしプログラマーが意図的に隠蔽を行うのであれば、そう、この発言は無意味であり、何の有用な情報も提供しない。一方、過失によって偶然に隠されていた場合は、この発言によって、その誤りを早期に発見することができます。

Andrei01:

隠蔽は変数のローカルコピーが作成されたときにのみ発生し、これも完全に正当な行為である。この隠蔽により、突然コードにエラーが発生しても、すぐに同じ名前で検索されるため、まさに発見しやすいのです。もし、このルールをコンパイラの論理で「解決」するために、関数テンプレートの名前を変更・改変し始めたら、エラー検索の状況はもっと複雑になり、コードの理解に混乱が生じるでしょう。当たり前のようですが。

ローカル変数と パラメータは1つのスコープにあるので、パラメータがこの名前であろうとローカル変数であろうと関係ありませんが、いずれにせよこの名前は外部スコープでの名前を隠します。

非表示は変数のコピーとは関係なく、エンティティ名と関係があります。そう、型などの実体名に関するものでも。

class A { };

void f(int a) {
        A x;
}

がコンパイルされます。

$ icpc -c 1.cpp
$ 

そして、これ。

class A { };

void f(int A) {
        A x;
}

そんなことはない。

$ icpc -c 1.cpp
1.cpp(4): error: expected a ";"
        A x;
          ^

compilation aborted for 1.cpp (code 2)
$ 

なぜなら、関数内のAという名前は、もはや型名ではなく、変数・パラメータ名だからです。外部スコープで宣言された型名が、変数-パラメータ名で隠されるようになりました。このコードを見つけることで、間接的に垣間見ることができます。

class A { };

void f(int A) {
        A++;
}

はよくコンパイルされます。

$ icpc -c 1.cpp
$ 

MQL4+では、変数・パラメータ名で型名を隠蔽する段階、すなわち関数本体が空でもコンパイルされません。

#property strict

class A { };
void f(int A) { }
void OnStart() { }

の結果です。

'A' - structure identifier cannot be used       3.mq4   4       12
'A' - structure identifier cannot be used       3.mq4   4       12

なぜだかわからないが、まったく驚かない。

一方、C++の場合は、このようなコードでも問題はない。

class A { };
void f(int A) { }

コンパイルの結果

$ icpc -c 1.cpp
$ 

この例では、隠蔽がエンティティ名に関係し、それ以外のものには関係しないことがわかります。

発言が切り替えられないと、エイリアシングなどいろいろと工夫しなければなりません。しかし、インテルコンパイラのようにターナブルであれば、そのような問題は起きません。

MQL4+の問題は、ネストしたスコープでの名前の隠蔽を検出するコンパイラの機能そのものにあるのではなく、この機能の根本的な操作性の悪さにあるのです。

 
Renat:

だから、警告についてクレームをつけるのではなく、自分自身のコードを修正すべきなのだ。

議論されている警告/注意書きについての不満は、原則的に除外できないことについてのものである、と私は考えています。

また、当然ながら、言語の中で何をすべきで、何をすべきでないかをプログラマーに指示することはできない。

 

このようなメッセージ(グローバル変数の 隠蔽)は、C++では意味がありません(mqlはc++ライクと宣言されていましたね)。例えば、こんな理由です。

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}
 
Pavlick:

このようなメッセージ(グローバル変数の隠蔽)は、C++では意味がありません(mqlはc++ライクと宣言されていましたね)。例えば、こんな理由です。

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}

C++は、MQL4+には構造体/クラステンプレートがなく、関数テンプレートのみであるため、ここで取り上げられたのでしょうか。

開発者の方がご存じかどうかわかりませんが、MQL4+でもクラステンプレートは可能です(ただし、大きな制約があります)。特にこの例は、次のようにMQL4+に置き換えることができます(メソッド内のローカル 変数の代わりにパラメータも使用します)。

#property strict

struct S1 { };
struct S2 { int val; };

template <typename T>
void f(T &t) {
  struct SS: public T {
    int f(int val) { return val; }
  } ss = {0}; // Переменная типа SS
}

void OnStart() {
  S1 s1; f(s1);
  S2 s2; f(s2);
}

コンパイル時に名前の非表示に関する警告が1つ表示されます。

'3.mq4' 3.mq4   1       1
struct has no members, size assigned to 1 byte  3.mq4   3       8
struct has no members, size assigned to 1 byte  3.mq4   8       10
declaration of 'val' hides member declaration at line 4 3.mq4   9       15
0 error(s), 3 warning(s)                1       4

OnStart()の最後の重要な行をコメントアウトすると、名前の非表示に関する警告が消えます。

 
simpleton:

C++がここで取り上げられたのは、MQL4+には構造体・クラステンプレートがなく、関数テンプレートしかないため?

...

一般的にはそうですが、µlを使うことも可能です。

struct S1{
    int val;
};

struct S2{};

#define INSTANTIATE(_Name, _T)          \
    struct _Name : _T                   \
    {                                   \
        int f() {int val; return val;}; \
    }

INSTANTIATE(SS1, S1);
INSTANTIATE(SS2, S2);

void start(){
    SS1 q1; q1.f();
    SS2 q2; q2.f();
}