アカウント名:
パスワード:
地獄継承クラスを見せられて俺のコードの方が綺麗だ、いやそれ違うだろう・・・とか理解できない?いや、これ有名なイディオムなんですよ・・・とか理解できない?デザインパターンっていうのが有りましてね・・・とか余りの無知に疲れる(半笑)
C++は罠が多すぎてちゃんと理解してるプログラマなんかこの世に存在しないだろ。例が悪すぎる。
C++のえらい人達ほど理論だけで実戦でコード書いてないからあてにならん。
C++ の標準化課程で、委員会の提案した仕様についてコンパイラ屋がダメ出ししてたのを見て、開かれているなと思うのと同時に、他の仕様もとりあえず動いてるだけなんじゃないかと疑うようになりましたよ。
> 他の仕様もとりあえず動いてるだけなんじゃないかと疑うようになりましたよ
実際、絶対やっちゃいけないけど、文法的には正しいとかいう機能が沢山ありますからねえ。(virtual なメソッドがあるクラスなのにデストラクタが virtual ではないとか、デストラクタ内でメンバを delete しているクラスなのにデフォルトのコピーコンストラクタを使ってるとか)
Cのポインタだってやっちゃいけない操作あるじゃんって話もあるけど、C++はCと比べても落とし穴の数が多すぎて、C以上に怖いような。超優秀なメンバーだけ揃ってる開発チームなら超強力な言語なんでしょうけど。
非常に危険なコードですよ、それ。
virtual 使ってるってことはすなわち、基底クラスへのポインタ経由であれこれ操作することを意味します。(基底クラス経由で操作する可能性がゼロなら、virtual にする必要がない)当然、delete することも想定すべきです。
例外的に決して delete されないこともあるだろうし、C++の設計思想として、少しでも効率を向上できる可能性がある場合には、そうできるようにしておくっていうのも知ってるけど、開発者の能力が揃ってないような現場を考えた場合、その設計思想が危険なコードを許す結果になってるってことは議論の余地がないと思います。
ほとんど使わない危険な機能はそもそも提供しない方が、一般の開発現場や、保守を長期にわたって行う状況では望ましいと思います。そして、C++の設計思想はそういう開発現場に向けたものではない。
> まず、私が出した例では、クラスAのデストラクタはprotectedですので、クラスBを外部から使用する限り、A*に対してdeleteすることは不可能です。
しかしクラスAのメンバ関数内で、delete することはできますよね。型安全性の保証としては不十分です。もちろん、熟練したC++プログラマのみで構成されるプロジェクトであれば、問題ありませんが。
> それはC++に求めるべきものではないです。
その点、すなわちC++はそういう安全性を求める言語ではないというのは、元から同意している点です。
ちなみに、他のオブジェクト指向言語を見ると、そもそも virtual などという予約語に相当する機能のある言語はほとんどないのです。大多数のオブジェクト指向言語は、C++で常にvirtualを指定するのと等価な言語仕様をもっているわけです。C++でvirtual指定を省略した場合の効率も、現代の技術なら link time optimization でかなりの部分実現できるでしょう。
C++は、それでも実現できないような、厳しい性能要件を達成するために、熟練したプログラマーのみで利用するという条件下では、非常に優れた言語です。その条件の成立しない状況では、他の言語を選択したほうが幸せでしょう。
あるいは、 #2304967 で挙げているようなコーディングを、規約やコンパイラオプションで禁止するかですね。C++の有名な解説書(Effective C++)でも、禁止を勧めていたはずです。
protectedな非virtualデストラクタの主な適用対象は、基底クラスにvirtual関数が全くない場合だと思います。基底クラスの分のvtableを完全に省略できることがその理由です。
この例だと基底クラスAはほかにvirtual関数を持っており(どのみちAのvtableが必要)、デストラクタを非virtualにする有難みがあまりないので、そこまでしなくてもいいのではかな(素直にAのデストラクタをvirtualにする)と私なら思います。
なお、protectedな非virtualデストラクタ自体は熟練というほどでもないテクニックだと思います。More Exceptional C++やModern C++ Designに取り上げられているようです(私は残念ながらどっちも読んだことがない)。最も単純な例がnoncopyable(More C++ Idioms/コピー禁止ミックスイン(Non-copyable Mixin) [wikibooks.org])でしょう。
#2306317 のACです。
> この例だと基底クラスAはほかにvirtual関数を持っており、デストラクタを非virtualにする> 有難みがあまりないので、そこまでしなくてもいいのではかなと私なら思います。と私なら思います。
ですよね。私もそう思いますし、Effective C++ もそういう感じの趣旨だったかと思います。にも関わらず、言語仕様的には非 virtual を許してますし、Phorkさんのように、virtualメンバ関数のある基底クラスのデストラクタを非virtualにすることも実際に行っていると主張する方がいるわけです。こういう状況で、プログラマの質や意見の揃わない、ある程度大
>> C++は、それでも実現できないような、厳しい性能要件を達成するために、熟練したプログラマーのみ>> で利用するという条件下では、非常に優れた言語です。その条件の成立しない状況では、他の言語を>> 選択したほうが幸せでしょう。
> であるならば、なおさら絶対だめというのは納得いかないですね。そういうときこそ禁止されたら困ると思うんですけど。
まあC++で開発するのが適切なプロジェクトで、性能プロファイルをとった結果、virutalをつけるかつけないかで、意味のある性能差が出るのであれば、許してもいいと思います。そういう意味では絶対だめ
私もどちらかというと性能は気にするほうですが、virutalのあるなしで変わるような定数倍のコストは、設計・コーディング時は気にしません。その段階で気にするのは、計算量的なコストだけです。
実際に動かしてみて性能が足りない場合には、プロファイルをとって、ボトルネックとなる部分だけを局所的にチューニングします。最適化を最後にやるのは、Knuthの勧め
> まずvirtual縛りで開発して、あとで非virtualに変えるのだとすると、> どこを非virtualにしても大丈夫か調べなければならないわけで、> 動作速度が逼迫したときその手間がかかるリスクを負うならば、> 最初から必要のないところでは非virtualにしておけという話になってしまいます。
このあたりは、プロファイラが気軽に使えるプラットフォームか否かで変わってきそうですね。
> あ、-Wallだったりは必要なのでデフォルトじゃないですね。すいません。> 以前gccで-Wno-non-virtual-dtorをつけないと警告が出たのですが、> 変わったのでしょうか。そのときのバージョン
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
ソースを見ろ -- ある4桁UID
C++なんかだと良くあるw (スコア:0)
地獄継承クラスを見せられて俺のコードの方が綺麗だ、いやそれ違うだろう・・・とか
理解できない?いや、これ有名なイディオムなんですよ・・・とか
理解できない?デザインパターンっていうのが有りましてね・・・とか
余りの無知に疲れる(半笑)
Re: (スコア:0)
C++は罠が多すぎてちゃんと理解してるプログラマなんかこの世に存在しないだろ。例が悪すぎる。
Re: (スコア:0)
Re: (スコア:0)
C++のえらい人達ほど理論だけで実戦でコード書いてないからあてにならん。
Re: (スコア:0)
C++ の標準化課程で、委員会の提案した仕様についてコンパイラ屋がダメ出ししてたのを見て、開かれているなと思うのと同時に、他の仕様もとりあえず動いてるだけなんじゃないかと疑うようになりましたよ。
Re: (スコア:0)
> 他の仕様もとりあえず動いてるだけなんじゃないかと疑うようになりましたよ
実際、絶対やっちゃいけないけど、文法的には正しいとかいう機能が沢山ありますからねえ。
(virtual なメソッドがあるクラスなのにデストラクタが virtual ではないとか、デストラクタ内でメンバを delete しているクラスなのにデフォルトのコピーコンストラクタを使ってるとか)
Cのポインタだってやっちゃいけない操作あるじゃんって話もあるけど、C++はCと比べても落とし穴の数が多すぎて、C以上に怖いような。
超優秀なメンバーだけ揃ってる開発チームなら超強力な言語なんでしょうけど。
絶対? (スコア:1)
class A {
protected:
~A() {}
public:
virtual void f() = 0;
};
class B : private A {
private:
virtual void f();
public:
A* a() { return this; }
};
とかやりませんか?
Re: (スコア:0)
非常に危険なコードですよ、それ。
Re: (スコア:1)
Re: (スコア:0)
virtual 使ってるってことはすなわち、基底クラスへのポインタ経由であれこれ操作することを意味します。
(基底クラス経由で操作する可能性がゼロなら、virtual にする必要がない)
当然、delete することも想定すべきです。
例外的に決して delete されないこともあるだろうし、C++の設計思想として、少しでも効率を向上できる
可能性がある場合には、そうできるようにしておくっていうのも知ってるけど、開発者の能力が揃ってない
ような現場を考えた場合、その設計思想が危険なコードを許す結果になってるってことは議論の余地がない
と思います。
ほとんど使わない危険な機能はそもそも提供しない方が、一般の開発現場や、保守を長期にわたって行う状況
では望ましいと思います。そして、C++の設計思想はそういう開発現場に向けたものではない。
Re: (スコア:1)
これは全くそう思いませんね。
まず、私が出した例では、クラスAのデストラクタはprotectedですので、クラスBを外部から使用する限り、A*に対してdeleteすることは不可能です。
そもそもdeleteは危険な操作です。対象となるポインタがdeleteできるものかどうかは常に注意を払われるべき問題です。deleteしてよいタイミングであるかどうかに加え、オブジェクトがnewで生成されたのか、スタック上に構築されたのか、placement newで構築されたのか、そのいずれのポインタであるかを言語上は区別できません。その判断をする能力が開発者に備わっていないというなら、deleteも生のポインタも禁止してスマートポインタ一本でやっていくほうがよほど安全でしょう。
設計思想が危険なコードを許す結果になっているのはその通りですが、その設計思想ゆえ、virtual関数を持つクラスのデストラクタは常にvirtualであるべきという主張には強く反対です。それはC++に求めるべきものではないです。
Re:絶対? (スコア:0)
> まず、私が出した例では、クラスAのデストラクタはprotectedですので、クラスBを外部から使用する限り、A*に対してdeleteすることは不可能です。
しかしクラスAのメンバ関数内で、delete することはできますよね。
型安全性の保証としては不十分です。
もちろん、熟練したC++プログラマのみで構成されるプロジェクトであれば、
問題ありませんが。
> それはC++に求めるべきものではないです。
その点、すなわちC++はそういう安全性を求める言語ではないというのは、元から同意している点です。
ちなみに、他のオブジェクト指向言語を見ると、そもそも virtual などという予約語に相当する機能の
ある言語はほとんどないのです。大多数のオブジェクト指向言語は、C++で常にvirtualを指定するのと
等価な言語仕様をもっているわけです。
C++でvirtual指定を省略した場合の効率も、現代の技術なら link time optimization でかなりの部分
実現できるでしょう。
C++は、それでも実現できないような、厳しい性能要件を達成するために、熟練したプログラマーのみ
で利用するという条件下では、非常に優れた言語です。その条件の成立しない状況では、他の言語を
選択したほうが幸せでしょう。
あるいは、 #2304967 で挙げているようなコーディングを、規約やコンパイラオプションで禁止するか
ですね。C++の有名な解説書(Effective C++)でも、禁止を勧めていたはずです。
Re:絶対? (スコア:1)
それはクラスAの用途と実態がマッチしてないだけです。クラスAのメンバ関数内でdeleteするなら当然デストラクタをvirtualで宣言するでしょうし、そうなったらnewでしかオブジェクトが作られないように、Bのコンストラクタもprotectedなりprivateなりにして、staticメンバ関数中でnewするといった対策も取られるでしょう。
が、そこまでやっても抜け道がどこかにあって安全性が100%でないのはC++である以上どうしようもないです。メンバ変数のポインタもdeleteできるから安全じゃないよね?とか明らかに普通じゃない書き方を引き合いに出されたらキリがない。性能と安全性を天秤にかけて、安全性のほうが重要だとなればローカルルールで禁止するのは結構ですが、ちょっとでも誰かが危険なコードを書く余地があるから何人たりとも絶対だめだというのはおかしいでしょう。
> C++は、それでも実現できないような、厳しい性能要件を達成するために、熟練したプログラマーのみ
> で利用するという条件下では、非常に優れた言語です。その条件の成立しない状況では、他の言語を
> 選択したほうが幸せでしょう。
であるならば、なおさら絶対だめというのは納得いかないですね。そういうときこそ禁止されたら困ると思うんですけど。
> あるいは、 #2304967 で挙げているようなコーディングを、規約やコンパイラオプションで禁止するか
> ですね。C++の有名な解説書(Effective C++)でも、禁止を勧めていたはずです。
デフォルトでwarningを出すコンパイラがほとんどなんじゃないでしょうか。もちろん私はoffにしますが。
繰り返しますが、ローカルルールで禁止するのはいいですよ。でも、絶対じゃない。
Re:絶対? (スコア:2)
protectedな非virtualデストラクタの主な適用対象は、基底クラスにvirtual関数が全くない場合だと思います。基底クラスの分のvtableを完全に省略できることがその理由です。
この例だと基底クラスAはほかにvirtual関数を持っており(どのみちAのvtableが必要)、デストラクタを非virtualにする有難みがあまりないので、そこまでしなくてもいいのではかな(素直にAのデストラクタをvirtualにする)と私なら思います。
なお、protectedな非virtualデストラクタ自体は熟練というほどでもないテクニックだと思います。More Exceptional C++やModern C++ Designに取り上げられているようです(私は残念ながらどっちも読んだことがない)。最も単純な例がnoncopyable(More C++ Idioms/コピー禁止ミックスイン(Non-copyable Mixin) [wikibooks.org])でしょう。
Re: (スコア:0)
#2306317 のACです。
> この例だと基底クラスAはほかにvirtual関数を持っており、デストラクタを非virtualにする
> 有難みがあまりないので、そこまでしなくてもいいのではかなと私なら思います。と私なら思います。
ですよね。
私もそう思いますし、Effective C++ もそういう感じの趣旨だったかと思います。
にも関わらず、言語仕様的には非 virtual を許してますし、Phorkさんのように、virtualメンバ関数のある
基底クラスのデストラクタを非virtualにすることも実際に行っていると主張する方がいるわけです。
こういう状況で、プログラマの質や意見の揃わない、ある程度大
Re: (スコア:0)
>> C++は、それでも実現できないような、厳しい性能要件を達成するために、熟練したプログラマーのみ
>> で利用するという条件下では、非常に優れた言語です。その条件の成立しない状況では、他の言語を
>> 選択したほうが幸せでしょう。
> であるならば、なおさら絶対だめというのは納得いかないですね。そういうときこそ禁止されたら困ると思うんですけど。
まあC++で開発するのが適切なプロジェクトで、性能プロファイルをとった結果、virutalをつけるかつけないかで、意味のある性能差が出るのであれば、許してもいいと思います。
そういう意味では絶対だめ
Re:絶対? (スコア:1)
Re: (スコア:0)
#2306317 のACです。
私もどちらかというと性能は気にするほうですが、virutalのあるなしで変わるような
定数倍のコストは、設計・コーディング時は気にしません。
その段階で気にするのは、計算量的なコストだけです。
実際に動かしてみて性能が足りない場合には、プロファイルをとって、ボトル
ネックとなる部分だけを局所的にチューニングします。
最適化を最後にやるのは、Knuthの勧め
Re:絶対? (スコア:1)
> 出るケースを経験されたのでしょうか?
比べたことはないです。
まず非virtualで開発して、その後virtualをつけるという手順でやるのだとすると、遅くなることはあっても速くなることがないので、わざわざ試す機会はなかなか来ない気がします。かといって、まずvirtual縛りで開発して、あとで非virtualに変えるのだとすると、どこを非virtualにしても大丈夫か調べなければならないわけで、動作速度が逼迫したときその手間がかかるリスクを負うならば、最初から必要のないところでは非virtualにしておけという話になってしまいます。
デストラクタではないのですが、あるプラットフォームのあるC++コンパイラ(代替はない)で、最初は仮想関数を使用していたが、オーバーヘッドが大きすぎてswitchに書き換えるハメになった、という話なら聞いたことがあります。(以後そのプラットフォームではC++を使用せずCで開発することになった・・・)
> Linuxを含むUNIX系OSではメジャーだと思われる gcc 4.6.3 の場合、デフォルト、あるいは
> -Wall オプションつきだけでは警告が出ません。
あ、-Wallだったりは必要なのでデフォルトじゃないですね。すいません。以前gccで-Wno-non-virtual-dtorをつけないと警告が出たのですが、変わったのでしょうか。そのときのバージョンは覚えていませんが・・・
手元のMSVC2010Expressだと/Wallで警告が出ます。
> お一人で開発されているのでしょうか?
> それとも複数人で開発されてますか?
今は一人ですが、以前勤めていたゲームメーカーでこのようにしていたので、引き続き同じ方針でやっています。
Re: (スコア:0)
> まずvirtual縛りで開発して、あとで非virtualに変えるのだとすると、
> どこを非virtualにしても大丈夫か調べなければならないわけで、
> 動作速度が逼迫したときその手間がかかるリスクを負うならば、
> 最初から必要のないところでは非virtualにしておけという話になってしまいます。
このあたりは、プロファイラが気軽に使えるプラットフォームか否かで変わってきそうですね。
> あ、-Wallだったりは必要なのでデフォルトじゃないですね。すいません。
> 以前gccで-Wno-non-virtual-dtorをつけないと警告が出たのですが、
> 変わったのでしょうか。そのときのバージョン
Re:絶対? (スコア:1)
> うちのようにスキルがデコボコしているチームだと無理ですので。^^;
件の会社でも新入社員のレベルはまちまちだったのですが、家庭用ゲーム機ですとメモリ管理が厳格なので、どうしてもヒープ周りの扱いは正しく身につけてもらわなければならないという切実な事情はありました。STLが原則使用禁止だったりして、好きなときにnew/deleteできる環境でC++を覚えた人からするとかなり異質な世界なので、もしかすると、あえて間違える余地を残すことで指摘の機会をつくるという効果もあったのかもしれないですね。