アカウント名:
パスワード:
CもC++もそんなことはやってくれないよ?所有権はプログラマが自分で管理するか管理するためのコードを書く。これ基本。でないとメモリリークし放題。
new/deleteの多くがコンストラクタ/デストラクタに置き換えられます。
なんてことはないし、
これらを使うとnew/deleteの多くがコンストラクタ/デストラクタに置き換えられます。そしてコンストラクタは変数の宣言時、デストラクタは変数がスコープを抜けるときに自動的に実行されます。プログラマは適切なデータ型とスコープに注意することでメモリリークを防げます。
なんて、インスタ
「スマートポインタ」は言語仕様ではない。
そう見えるようにクラスを組んであるだけであって、それはポインタじゃない。
さらに言えばnewの後にコンストラクタ、deleteの前にデストラクタが呼ばれるんであって、インスタンスと参照を混同してないか?
そうでないと言うならそのとき何が起きてるのか一実装例でいいから説明してみ?
{ string message( "Hello, world." ); cout << message << endl;}
{ vector<string> messages; messages.push_back( string( "Hello," ) ); messages.push_back( string( " " ) ); messages.push_back( string( "World." ) ); for( vector<string>::const_iterator itor = messages.begin(); itor != messages.end(); itor++ ) cout << *itor; cout << endl;}
>動的オブジェクトの所有権管理CもC++もそんなことはやってくれないよ?所有権はプログラマが自分で管理するか管理するためのコードを書く。これ基本。でないとメモリリークし放題。
Cならば文字列や配列といった「動的オブジェクトの所有権管理」がポインタを使用して必要となるが、C++ならばオブジェクトとして管理される例。
元コメントは言語仕様がどうのとは言っていません。逆に「スマートポインタ」と明言しています。後から出てきて対象範囲を狭めるのはなぜですか? それにスマートポインタは標準C++ライブラリの一部です。
そういうことを言っている訳じゃありません。適切なデータ型を選択することによって多くの場合new/deleteを呼ばなくてもいい、動的オブジェクトの管理から解放されると言っています。
そう、本来ポインタで表現することが苦しいものもCではポインタとして表されている。これこそ元コメントで「これら全然違う概念を一個で実現しようとする、そもそも無茶なキメラですよ。」と言われていることです。tarosukeさんも理解してるじゃないですか。
ほんとーにコメント読まずにコメントしてるなー
俺には管理するためのインスタンスが生成/消滅するのに伴って実体の方のインスタンスをnew/deleteしているように見えるがな。
んじゃさ、その(どっちでもいいけど)messageを何か他のインスタンスへ引数として渡すことを考えてみてー。渡す先は今いる関数が戻っても生きてるし、その引数(あるいは少なくともそれと同値なモノ)を後々まで使うという条件でね。
messages.push_back( string( "Hello," ) );
vector<string> messages;{ string message( "Hello," ); messages.push_back( message ); // 何か他のインスタンスへ引数として渡す} // 渡す先は今いる関数が戻っても(関数ではないがブロックスコープを抜けている)...
C++でポインタじゃないから何?
どれも反論になってないよ。
そのパターンがすでに書かれていることも読み取れないレベルなんですね。
deleteは記憶領域を返却するだけでなく、デストラクタも走ることをご存知ないですか?
だから何?デストラクタが走るのと所有権管理にどんな関係があると?ポインタを複製してもちゃんと管理してくれるとでも?というかデストラクタを書くのは誰?...あー、書く必要がない人なのね。
ポインタは参照や反復子を実装する手段に過ぎないともいえますね。
言えない。順序が逆。既に上げてある通りポインタを反復子として使えない使い方もある。
抽象度が高い複雑な案件でも、パフォーマンスを上げたい部分は
newで生成されたオブジェクトを指すポインタは、それを削除するための情報も内包している。
例としては文字列でもいいけど、たとえば下みたいな構造体は「ポインタは先頭を指しているだけ」という性質を使ったもの。この場合はサイズが不正なのでポインタを反復子としては使えない。struct HOGE{ ほげふが char buff[0];};
こらこら、嘘を書いちゃいかん。 自動的に const int *buff; みたいな変数宣言がされ、buffが buff[0]を指すように初期化されると思っていますか? そんな高度なことは、C/C++コンパイラはやりません。 表記が違うだけで、&buff[0]もbuffも同じものを表します。
もしかすると、あなたは *(buf+2) と buf[2] を違うものだと考えてたりしませんか?
buffは&buff[0]を指すconstポインタ。
なるほど、sizeof(buf)のような時ですね。 C/C++の言語仕様そのものがすごくコンパクトに作られているのは認めますが、ミスを誘発するような仕様が幾つかあるのが残念ですね。 char s[20] = "hello world!"; なんて記述は、便利だけど酷い仕様です。
あなたの言う「配列の先頭を指すconstポインタ」を指すポインタ変数を定義し、どのように使うのか見せてください。
コンパイル時に解決されるか、ランタイム実行時に解決されるかは処理系依存です。 printf("%d\n", sizeof(buff)); の結果がどうなるかやってみ。 あなたの言うconstポインタとかいうもののサイズが分かるから。
&c の&は、"&演算子"です。&演算子は直後の変数のアドレスを取り出すという演算を行います。&cは、変数cのアドレスを求めるという演算です。 &cを、コンパイル時に相対アドレスとして解決する処
レジスタ変数のアドレスを取得可能な処理系を使ったことがある。 register変数は必ず、CPUレジスタ上に置かねばならないという規約はないので、変数のアドレスをとるような処理がある場合はメモリ上にその変数の領域を確保するようにしていたようです。そもそもregisterという概念そのものがないCPUも存在するし、register変数をどのように実現するかは処理系依存だと思います。C言語の規約には、どのように動作するのが望ましいということが、書かれていそうです。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
人生の大半の問題はスルー力で解決する -- スルー力研究専門家
まぁ、驚いたのは (スコア:0)
指摘されても問題が何か理解出来ていない編集にはビックリだな
Re: (スコア:2, 興味深い)
自分でプログラミングすることなんか全く無いんでしょうね。
Re: (スコア:1, すばらしい洞察)
ポインタがいまいち理解できない人には朗報だ。
Re: (スコア:0, すばらしい洞察)
それで正しいと思います。
Cのポインタは、
- スカラ値への参照
- 配列への参照
- 動的オブジェクトの所有権管理
- 反復子
これら全然違う概念を一個で実現しようとする、そもそも無茶なキメラですよ。
私はC++使いなんですが、C++なら、状況によって参照やスマートポインタや反復子を使い分けるところです。
理解しようとするとかえって遠回りだと思います。
Re:まぁ、驚いたのは (スコア:1, すばらしい洞察)
>動的オブジェクトの所有権管理
CもC++もそんなことはやってくれないよ?
所有権はプログラマが自分で管理するか管理するためのコードを書く。これ基本。でないとメモリリークし放題。
んとなー?抽象度の高い方から理解しようとするから理解できないんだよ。
ポインタを理解するにはメモリイメージを持つこと。これに尽きる。
Re:まぁ、驚いたのは (スコア:1)
# さりげなく「スマートポインタ」と書かれているから。
これらを使うとnew/deleteの多くがコンストラクタ/デストラクタに置き換えられます。そしてコンストラクタは変数の宣言時、デストラクタは変数がスコープを抜けるときに自動的に実行されます。プログラマは適切なデータ型とスコープに注意することでメモリリークを防げます。
これらの長所・短所を理解した上で相手に対して「んんー?あんたホントにC++使い?」と発言されているのでしょうか?
Re: (スコア:0, フレームのもと)
さらに言えばnewの後にコンストラクタ、deleteの前にデストラクタが呼ばれるんであって、
なんてことはないし、
なんて、インスタ
Re: (スコア:0)
># さりげなく「スマートポインタ」と書かれているから。
tarosuke氏が噛みついてるのはその前、Cのポインタはキメラだって主張の部分。
他の言語で何がどう実装されていようが、そんなの関係ない。
あなたの反論、ですらないが、はピントがずれてる。
Re:まぁ、驚いたのは (スコア:1)
Re:まぁ、驚いたのは (スコア:1)
んじゃさ、その(どっちでもいいけど)messageを何か他のインスタンスへ引数として渡すことを考えてみてー。渡す先は今いる関数が戻っても生きてるし、その引数(あるいは少なくともそれと同値なモノ)を後々まで使うという条件でね。 「選択」ねぇ...ま、誰かが作ったラッパにくるまれたものだけ使ってればいいんならポインタも参照も確保も解放も意識する必要はないわな。 ほんとーにコメント読まずにコメントしてるなー。だから順序が逆だってーの。
Re:まぁ、驚いたのは (スコア:1)
元コメントで「スマートポインタ」と書かれているにもかかわらず、勝手に「スマートポインタはC++言語仕様ではない」とか言い出すし。言語仕様でないから何?
「C++なら、状況によって参照やスマートポインタや反復子を使い分けるところ」をCならポインタで実現せざるを得ないと書かれているのに、「「スマートポインタ」はただのクラスであってポインタなんかじゃない」とか言い出すし。C++でポインタじゃないから何? だれもスマートポインタがポインタかどうかの話はしてません。
どれも反論になってないよ。 だから何? 「メモリリークし放題」への反論なんだからメモリリークしなければそれで説明できている。単にtarosukeさんがC++のメモリリークのしない/しづらくできる一面を知らなかっただけでしょう。new/deleteがどうの「メモリリークし放題」なコードしか書けないんでしょ。 そのパターンがすでに書かれていることも読み取れないレベルなんですね。 vector<string>::push_back()関数にstringを渡してます。そしてstring消滅後にforループでこのstringを読み出してますよ? こうやって書いてあげないと読み取れないかな?
こんな程度の人が他人に対して「んんー?あんたホントにC++使い?」と言うのはどうかと思います。
Re:まぁ、驚いたのは (スコア:1)
誰かが用意してくれたライブラリにくるまってHowTo知識があれば満足だと言うなら、もう「迷惑だからC/C++はやめれ。Javaがお勧め」くらいしか言うことはないよ。
Re:まぁ、驚いたのは (スコア:1)
あとtarosukeさんは反論でなく粘着してるだけらしいですね。春なのかなぁ。
Re: (スコア:0)
明示的にdeleteするのも所有権管理の範疇ではないでしょうか?
>ポインタを理解するにはメモリイメージを持つこと。これに尽きる。
その通りです。抽象度の高い課題には不要な理解で、生産性を下げます。
Re:まぁ、驚いたのは (スコア:1)
感覚の問題かも知れんが、少なくとも俺はそうは思わない。
なぜならその例でいうdeleteで言えばnew/deleteとは無関係にポインタでアクセスできてしまうから。
「*(int*)0 = 0;」みたいないきなり「ぬるぽガッ」なコードだって書けちゃうし。
もしnew/deleteを所有権の管理とするなら所有する主体(主語)はオブジェクトではなくプロセスという解釈が必要になる。
でも、そうだとしてそれに意味があるのかどうかはかなり疑問。
>抽象度の高い課題には不要な理解で、生産性を下げます。
不要かどうかは別にして、それはそう。
だからそういう課題でパフォーマンス的にも細かい事言われないならC/C++はそもそも不向き。
Re: (スコア:0)
>「*(int*)0 = 0;」みたいないきなり「ぬるぽガッ」なコードだって書けちゃうし。
その通りです。所有権管理と参照は分離されるべきなのです。
だけどCのポインタは分離されてないよね、というのが前言の趣旨です。
>だからそういう課題でパフォーマンス的にも細かい事言われないならC/C++はそもそも不向き。
パフォーマンスが重要な案件でも、チューニングが必要なのは一部です。
Re: (スコア:0, フレームのもと)
分離されてないも何もさっきから言ってるように、そもそもポインタには所有権管理機能なんてないんだってば。
new/deleteやmalloc/freeはプロセスがメモリ空間を占有するものであって、ポインタがその確保した領域を占有するというものではないよ。
そもそもポインタは先頭を指してるだけであって領域のことなんか知ったこっちゃない。
例としては文字列でもいいけど、たとえば下みたいな構造体は「ポインタは先頭を指しているだけ」という性質を使ったもの。
この場合はサイズが不正なのでポインタを反復子としては使えな
Re: (スコア:0, フレームのもと)
だから何?デストラクタが走るのと所有権管理にどんな関係があると?
ポインタを複製してもちゃんと管理してくれるとでも?
というかデストラクタを書くのは誰?
...あー、書く必要がない人なのね。
言えない。順序が逆。
既に上げてある通りポインタを反復子として使えない使い方もある。
Re:まぁ、驚いたのは (スコア:1)
たしかにnewすると確保サイズが保存されてdeleteでちゃんと戻してくれる。でもそれはポインタの機能じゃなくてnewとdeleteの機能。ポインタに確保サイズとか入ってる糞な処理系の存在を否定はしないけど普通の処理系ではポインタに入ってるのはアドレスだけだよ。それと別のところにも書いたけど「スマートポインタ」はただのクラスであってポインタなんかじゃないよ。 なーんて言ってるし、やっぱり件の記事と大差ないな。
Re: (スコア:0)
「FILE*はfopen()やfclose()の機能であってファイルハンドル管理とは無関係」
というわけか。
ハハハハハハハハ
Re:まぁ、驚いたのは (スコア:2, すばらしい洞察)
Javaが生まれたということはよく分かった。
優秀なエンジニア二人の手を止めてしまう訳か。
# お前らがポインタを知っている事はよく分かった。
# でも人に誤解しないように説明するスキルはそれと別だからな、ということ。
Re: (スコア:0)
学習してもC/C++のポインタ程度の事柄を理解できない人は、ポインタ以外の技術も理解できないと思う。
(大半のPGは技術を理解してる必要も無いんだけどね)
Re: (スコア:0, フレームのもと)
そういう結論に至った経緯に興味があるよ。書いてみ?
Re: (スコア:0)
この構造体のどこにポインタがでてくるの?
配列の識別子は、単体で表記する場合に、配列の先頭要素のアドレスと解釈されるという特例(&buff[0]の短縮表記)があるけど、
先頭アドレスのことをポインタと言ってるんじゃないよね?
ひょっとして、アドレスとポインタの区別が付いてない?
Re: (スコア:0)
>ひょっとして、アドレスとポインタの区別が付いてない?
つ【ブーメラン】
Re:まぁ、驚いたのは (スコア:1)
はしょりすぎて理解できなかったか?
Re: (スコア:0)
こらこら、嘘を書いちゃいかん。 自動的に const int *buff; みたいな変数宣言がされ、buffが buff[0]を指すように初期化されると思っていますか? そんな高度なことは、C/C++コンパイラはやりません。
表記が違うだけで、&buff[0]もbuffも同じものを表します。
もしかすると、あなたは *(buf+2) と buf[2] を違うものだと考えてたりしませんか?
Re:まぁ、驚いたのは (スコア:1)
Re: (スコア:0)
なるほど、sizeof(buf)のような時ですね。
C/C++の言語仕様そのものがすごくコンパクトに作られているのは認めますが、ミスを誘発するような仕様が幾つかあるのが残念ですね。
char s[20] = "hello world!";
なんて記述は、便利だけど酷い仕様です。
Re: (スコア:0)
これは酷い嘘。
「buffは&buff[0]を指すconstポインタ」ならば、&buffは、「&buff[0]を指すconstポインタ」のアドレスを返すとでも思ってるんでしょうか。
実在しないものは返せない。
ポインタとアドレスの区別をつけるのが、あなたの次のステップですね。
Re: (スコア:0)
たぶん、親コメを読んでないんでしょうが。
Re: (スコア:0)
あなたの言う「配列の先頭を指すconstポインタ」を指すポインタ変数を定義し、どのように使うのか見せてください。
Re: (スコア:0)
あなたの言う「配列の先頭を指すconstポインタ」に対して、sizeof演算子を実行したときの結果がどうなるか教えてください。
その理由も教えてね。
Re: (スコア:0)
Re: (スコア:0)
>
>あなたの言う「配列の先頭を指すconstポインタ」を指すポインタ変数を定義し、どのように使うのか見せてください。
あなたの要求する情報を格納する実メモリは存在しません。そんなコードを書くことは不可能です。
char c;
&cの値はcの格納されているアドレスを指すポインタですが、&cの値を格納しているメモリはありません。
&cがコード上に現れると、相対アドレスがコンパイル時のオフセット値を元に計算され、解決されます。
&c=NULL;といった代入はできないので、C言語の文法上、constポインタとして扱われます。
sizeof演算子はコンパイル時に解決されます。実行時解決はされません。
「実行」されてませんから質問の意味が不明です。
Re: (スコア:0)
>「実行」されてませんから質問の意味が不明です。
コンパイル時に解決されるか、ランタイム実行時に解決されるかは処理系依存です。
printf("%d\n", sizeof(buff)); の結果がどうなるかやってみ。
あなたの言うconstポインタとかいうもののサイズが分かるから。
Re: (スコア:0)
> &cの値はcの格納されているアドレスを指すポインタですが、&cの値を格納しているメモリはありません。
> &cがコード上に現れると、相対アドレスがコンパイル時のオフセット値を元に計算され、解決されます。
> &c=NULL;といった代入はできないので、C言語の文法上、constポインタとして扱われます。
&c の&は、"&演算子"です。&演算子は直後の変数のアドレスを取り出すという演算を行います。&cは、変数cのアドレスを求めるという演算です。
&cを、コンパイル時に相対アドレスとして解決する処
Re: (スコア:0)
>>「実行」されてませんから質問の意味が不明です。
>コンパイル時に解決されるか、ランタイム実行時に解決されるかは処理系依存です。
ちなみに、C99 では、文脈によっては(可変長配列)、必ず実行時解決になります。
Re: (スコア:0)
「(変数の)アドレスを指すポインタ」って理解すればいいです。
変数は変数でも記憶クラスがregisterだとポインタ使えないよ。
ポインタが指すのはあくまでもアドレス。
Re: (スコア:0)
うーん、動的に型定義できる言語とは聞いてたけど……
Re: (スコア:0)
レジスタ変数のアドレスを取得可能な処理系を使ったことがある。 register変数は必ず、CPUレジスタ上に置かねばならないという規約はないので、変数のアドレスをとるような処理がある場合はメモリ上にその変数の領域を確保するようにしていたようです。そもそもregisterという概念そのものがないCPUも存在するし、register変数をどのように実現するかは処理系依存だと思います。C言語の規約には、どのように動作するのが望ましいということが、書かれていそうです。
Re: (スコア:0)
register指定子は「可能ならレジスタに割り付ける」だけで、不可能なら単に無視されます。
register指定したにも関わらずメモリに割りついた変数のアドレスは取得できてもおかしくありません。
ただ、ソース上の指定がどうであれ、コンパイルの結果メモリに割り付けられたらレジスタ変数とは呼べません。
>register変数をどのように実現するかは処理系依存だと思います。
そもそもの話、メモリとレジスタをいかに活用するかはコンパイラの裁量ですよね。(volatileでない限り)
最適化次第では一旦メモリに割り付いた変数でもメモリに書き戻さず、レジスタ上で処理を続けたりするので
(記憶クラスが関数内で部分的に変化してる)もはやレジスタ変数という区分自体が意味を成さなくなってます。
#だからレジスタ変数という場合、純粋にレジスタに割り付く処理系が前提なのだと文脈で解釈して欲しい・・・
注釈 (スコア:0)
豊富な知識が邪魔をして、相手のコメントをよく読もうとしなかったのが敗因でしょう。