C++相談室 part134
■ このスレッドは過去ログ倉庫に格納されています
次スレを立てる時は本文の1行目に以下を追加して下さい。
!extend:on:vvvvv:1000:512
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。
前スレ
C++相談室 part133
http://mevius.5ch.net/test/read.cgi/tech/1511509970/
このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.102【環境依存OK】
http://mevius.5ch.net/test/read.cgi/tech/1509780815/
■長いソースを貼るときはここへ。■
http://codepad.org/
https://ideone.com/
[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)
VIPQ2_EXTDAT: default:vvvvv:1000:512:----: EXT was configured こんな名前空間もあるね
int x;
int main(void)
{
x = 1;
int x;
x = 2;
{
int x;
x = 3;
}
return 0;
} 謎すぎワロタがそこから上のスコープのxを参照してくれ std::mapのように文字列や構造体をキーにした高速アクセスができて、
要素の数が一定数を超えたらLRU形式で勝手に削除してくれる、
キャッシュのような機能を実装したいのだけど、
C++でそのような仕組みを作れるクラスはないですか? 自分で実装するならどうにでもなるだろ
そのための道具は全て標準で揃っている バックグラウンドならスレッド使うしかないんじゃないかな C++のプログラマーって性格ねじ曲がってるなあ
初めてGo応援したくなったわ >>137
どんな点が、性格悪い、と思わせるのですか? >>136
要素数が閾値を超えるのは要素が追加される時だからその時に古い奴を削除すりゃいいだけじゃね? >>135
簡単で良いのでサンプルコード書いてもらえませんか? >>135じゃないけどシンプルにいくなら
{
map<key,value> data; // 本来のデータ
map<key,list<key>::iterator> lruindex; //
list<key> lrulist; // LRUリスト
... // mapと同じインターフェイス
}
みたいなクラスで要素の追加・削除・参照とかの時にLRUリスト見て処理すればいい 辞書・線形リスト・2分木を、組み合わせる。Ruby で書くと、
class LRU_hash
def initialize (max_size = 3)
# ary は、hash に追加・アクセスした順
@hash = {}; @ary = []
@max_size = max_size
end
def push (key)
if @hash.has_key? key
# 一旦、要素を削除してから、最後尾に追加しなおす
@ary.delete key
else
if @max_size == @hash.size
# 先頭要素を削除してから、最後尾に追加する
@hash.delete(@ary.shift)
end
@hash[key] = true
end
@ary.push key
end
def print_buf
puts @ary.join ', '
end
end
ary = ["あ", "a", "あ", "い", "b", "あ", "c"]
hash = LRU_hash.new 4
ary.map { |key| hash.push key }
hash.print_buf #=> い, b, あ, c >>144
> # ary は、hash に追加・アクセスした順
参照のたびに最後尾に追加しなおすの? プログラムを作っていて困っています。
プログラム動作環境、windows 7 x86_x64
プロセスをExplorerを親として、
起動したプロセスにファイルの存在するディレクトリを作業ディレクトリとして
割り当てたい。
ただし、プロセスへのアタッチによる変更は禁止とする。
ようするにファイルをダブルクリックして起動するのと同じ状況を再現したいのです。
例
C:\hoge\fuga.exe
[現状]
Explorer C:\hoge\fuga.exe
親
explorer.exe
カレントディレクトリ
C:\Windows\System32\
[理想]
Explorer C:\hoge\fuga.exe
親
explorer.exe
カレントディレクトリ
C:\hoge\ >>145
>>134
で、LRU と書いてあるから、Hash に追加しようとした度に、
すでに存在する場合でも、配列の最後尾に追加しなおした
どういう意味か、正確にはわからないけど >>146
explorer.exeへのショートカットを作ってプロパティで作業ディレクトリを指定するか、
COMでIShellLink::SetWorkingDirectoryを使って同じことをするあたりか? みなさんありがとうございます。
std::mapにLRUや最大要素数の仕組みを持たせた派生クラスでも
無いかと思ったのですが、標準ではやっぱり無いですか。
>>143のように、std::mapをメンバの一つに持たせた独自クラスを
一から作っていくことになるんですかね。 amazonランキングの謎を解く とか言う本でmove-to-frontを見た
本の紹介「Amazonランキングの謎を解く」
http://www.kenkyuu.net/whatsnew/2011/08/book2011-08-01.html
>「move-to-front規則」(最後に売れた順に並べる、つまり、注文のたびに1位にジャンプする)
Move To Front - Wikipedia
https://ja.wikipedia.org/wiki/Move_To_Front >>149
「c++ lru map」でググったか?
いくつかサンプルになりそうなコードが見つかるんだけど C++を勉強しようと思ってる者ですが書籍を探しております。Cはある程度書けるのでそれを前提とした書籍が欲しいです C++ クイック入門&リファレンス
プログラミング言語C++ 第4版 >>155
C++11 以前だが accelerated c++, ここでフォローするよ 以下のようにconst char*型の文字列でchar*型の変数を初期化したいときに
strcpyやstrlenを書かずにstd::stringを利用して短くかけないかと思うのですが
msvcだとエラーにならず、clang, gccだとdeleteでセグメンテーション違反になります。
どうすればより良い感じになるでしょうか?const_castはできれば使いたくないです。
#include <string.h>
#include <string>
#include <iostream>
int main()
{
const char* asdf = "asdf";
// char* psz2 = new char[strlen(asdf)+1];
// strcpy(psz2, asdf);
std::string *psz = new std::string(asdf);
char* psz2 = &(*psz)[0];
std::cout << psz2 << std::endl;
delete psz2;
return 0;
} delete psz2なんてしちゃだめconst関係ない 何故stringそのものじゃなくて内部データをdeleteしようと思ったのか
newで確保した配列じゃないからdeleteはできない
stringの内部データは静的な配列と動的な配列を組み合わせて表現されている
mscvの場合先頭16文字はchar[16]でそれ以降は動的な配列に入るようになっている
psz[0]のアドレスはchar[16]の先頭アドレスなので当然deleteできない
msvcはdeleteに失敗しても落ちないのかな >>155-159
本格的な本なら、ロベール、ハーバート・シルトの独習
軽めの本なら、柴田 望洋、林 晴比古、猫 ハンガリー人まだ絶滅してないのか。
stringはnull terminatedでないからpszはおかしい。
psz2もnull terminatedの保証がないからc_strを使うべき。
うまくいったらstrdupも調べとこうな。 >>162
char* psz2 = &(*psz)[0]; って
char* psz2 = psz->c_str(); と同じなのかな?
いずれにせよ delete psz; は出来る(するべき?)だけど、
delete psz2; は出来ないんじゃないかな。 必要ないところでnew/delete使う人は根本からして何も分かってない >>162
お前はstringがただの配列だと思っているのか?
このトンチキ野郎! >>162
弁護士の唐沢です
しっかり「char* const」と「const char*」の違いを認識しなさい
const char*は参照先の定数を変更しない事を保証する宣言であり、char*は参照先の定数を変更できる為、const char*で保持するアドレスをchar*にコピーする事は言語仕様により禁止されています。それは分かるよね?
最初に宣言したポインタを間違えて別アドレスで上書きしないようにconstで固定したいのなら、char* constを使うようにしましょう。とりあえずとりいそぎ >>162
strdupという手があるが何がしたいのか今一つ分からない
const char* asdf = "asdf";
char *p = strdup(asdf);
std::cout << p << std::endl;
delete p; >>167
データは連続しているので同じになる
16文字まではスタックを使い、それ以上の長さになるとヒープにコピーされる
実装ではメンバの配列には何かしらのエスケープ文字が入る
ちなみにmsvcでは実装の都合上free(&str[0])で強引に解放できる 補足
スタックとヒープを使い分けるかどうかは実装依存
gcc、clang、msvcでは行われている
したがって短い文字列でnewを避けるためにstringを使わないというのは意味が無い >>171
strdupで確保した領域をfreeでなくdeleteするのは正しいの? >>175
弁護士の唐沢です
mallocとdeleteは併用厳禁です。freeを使用してください >>176
良くねえだろ ぼけ
>>179
開放はpublic的なニュアンスだよな >>162
ぶっちゃけた話、 strcpy が一番短いと思う。 >>182
strdup という答えが出てるのに何言ってるの? >>183
strdup は C++ の仕様の範囲内ではないので……。
POSIX と MSVCRT に有るからほとんどの場合に十分といえば十分なのかもしんないけど。 >>166
接頭辞を見ればデータ内容の属性がワカルというメリットは他に代え難い
ttp://local.joelonsoftware.com/wiki/間違ったコードは間違って見えるようにする
あといちいちthis->xと書くよりも、すすんでm_xと書きましょう strdup()だと明示的に開放コードをどっかに書かなくてはならなくて必ず忘れるので
せっかくC++なのでスマポ的にwrapすると良いと思う ホワイトボックスなCでは許せるが
ブラックボックスなC++の流儀には全く合わない
それがstrdup >>173-174 教えてくれてありがとう。
返されるアドレスは等しい値なのか、という単純な質問だったんだけど、
読み直してみたら分かりにくい質問文だと思っていた次第。
それにしても &(*psz)[0] って結構ややこしいのね。
オーバーロードされた[]演算子が返すcharへの参照、
に対してアドレス演算子&を作用させた結果、て感じかな。 すみません、たくさんレスありがとうございます。
_strdupにしてみたら期待の動作ができました。
ありがとうございました。 また質問してすみません。
msvc(vs2017)だとコンパイラをC++17にしても以下のプログラムで
C2664 'void (T *&)': 引数 1 を 'hoge *' から 'hoge *&' へ変換できません。
となってしまうのですが、コードにバグが有るでしょうか?msvcのバグでしょうか?
GCCやClangではコンパイルできます。
#include <memory>
struct hoge {};
template <class T>
inline void safe_delete(T*& p) {
if (p) {
delete p;
p = nullptr;
}
}
int main() {
std::unique_ptr<hoge, decltype(&safe_delete<hoge>)> sp{new hoge(), safe_delete<hoge>};
return 0;
} (T *&)
そもそも、ポインタ・参照を、同時に使えるのか? new hoge()は変数じゃないから、代入できない。 >>165
独習C++ はいいですね、特に演習問題「std::stringを再実装する」を絶賛します
これが書けるようになったらC++初級者をかたってもいいかもしれない、もしかすると解答は載ってなかったかもしれないけれども >>185
どこから引用したのか知らんけど、そのページ読んでないだろ…
システムハンガリアンはまるで役に立たないって書いてあるぞ。 >>194
(システム)ハンガリアンってそんなに悪いものなんですかねえ
いや、win32api がバンバンハンガリアンしているので、そんなもんか、と思っていましたが >>195
OOPともTMPとも型推論とも相性が悪いからね。
MS自身ももう使うなって言ってる。 嫌いだからハンガリアン意地でも使わなかった
dwやらszやらせっかくのフリーフォーマッとが台なしだよ >>191
それは「ポインタ変数の参照」で、たしか便利に使えた気がしますが…
明日にでもちょっと書いてみます、今日は疲れました… >>195
システムハンガリアンは弊害ばかりだろうけど、アプリケーションハンガリアンは適切に使えば有益だよ。 mとかいらなくねってなって削ったら_から始まるようになった データの属性としてサイズとか型そのものを明示したいときはシステムハンガリアンするしかないし、
よってWIN32APIがシステムハンガリアンを使って定義されるのは全く正しい
問題なのはアプリケーションハンガリアンすべきときと
システムハンガリアンすべきときが区別できない香具師が適当に使うと
被害甚大だということやがな… 今時システムハンガリアンは無いだろ
20年前で時間が止まってるのかよ >>205
なぜシステムハンガリアンが有り得ないのかkwsk
DWORDを渡すABIがある日突然気まぐれにUSHORTに変わったりしたら困りはしまいか ググればいいだろ
積極的批判
システムハンガリアンを使っているソースコードを修正してデータ型を変更した際、同時に変数名も変更するコストがかかる。変更を怠ると、たちまち不整合となり、保守の障害となるだけで一利もない。
C++やC#のような言語では型付けが存在するためにシステムハンガリアンを使用することによる利点はない[3]。
移植性を阻害する。
総称型、メタプログラミングとの相性が悪い。
消極的批判
いわゆる良書と呼ばれるようなC++本で、現在[いつ?]システムハンガリアンを採用している例が皆無。
かつてWindows API/MFCにおいてハンガリアンを全面的に採用していたMicrosoft自身が、.NET Frameworkではハンガリアンを禁止[1]している。 型なんてマウスオーバーなりすれば表示されるだろ
変数名に書いておかなきゃわからないとかメモ帳で書いてるのかよ >>190
デリータはポインタが指す先のリソースを後始末するのが仕事であって、
ポインタが無効になるという処理は unique_ptr の側でやってくれるので、
ヌルを代入する必要はない。
むしろ unique_ptr 内で管理しているものをデリータが勝手に弄るのは好ましくないので、
参照で受けるのはやめてさしあげろ。
私なりに仕様を読んでこの場合をエラーにする根拠は発見できなかったが、
エラーになってくれる方がありがたい場面だと思う。 デリータに渡されるのは左辺値と限らないからだろう。 N3337 だと 516 ページの説明がデリータの要件だと思うんだけど、
デリータ d の型が D で ptr の型が unique_ptr<T, D>::pointer のとき式 d(ptr) が valid であることと書いてあって、
ptr が rvalue か lvalue かってのは特に指定がない。 (どこかに書いてあったりする?)
この説明で言ってる ptr が変数名なのだとしたら暗に lvalue とほのめかしてるようにも思えなくもないし、よくわからん。
わからんことは避けて通りたい。 私なりの見解としては未定義だと思ってる。
未定義ならばやったらエラーになる方向にしてくれる方がありがたいという思い。 >>206
ABIにシステムハンガリアン関係ないだろ…
APIを指してるとして、呼び出し側はリファレンスマニュアルなりIDE機能なりを利用して引数の型情報も
システムハンガリアンが付いている仮引数名と同時に参照しているはずだよね?情報重複してるけど本当に必要?
仮引数名のシステムハンガリアンの有無に関わらず、APIのシグネチャは用意に変更してはならないものだけど、
そもそも仮引数名はシグネチャじゃないからシステムハンガリアンがついていたって何の保証にもならないよ? 重複する情報をコンパイラの支援なく一致させ続けることが出来るだろうか。 いや、できない。
って話よね。
まあ世の中にはそういうのを検査するツールとかもあるんだろうけどさぁ、
そういうツールを導入できる環境ならまともな IDE だって使えるだろう。 >>210
>>211
レスありがとうございます。
shared_ptrだと行けるのでなんかすればコンパイル通るのではないかと
思ったのですがだめなんですね〜。
普通に使う用とカスタムデリータに使う用と二種類用意してやり過ごしてみたいと思います。
template <class T>
inline void safe_release(T*& p) {
if (p) {
p->Release();
p = nullptr;
}
}
template <class T>
inline void custom_deleter(T* p) {
p->Release();
// p = nullptr; no meaning
} >>207
藻前はレスをきちんと読んでいないのではないか
>システムハンガリアンを使っているソースコードを修正してデータ型を変更した際、同時に変数名も変更するコストがかかる。(>>207)
に直接対応する元レス>>206は、
>データの属性としてサイズとか型そのものを明示したいとき(>>204)
について述べているのでデータ型変更時のコストを言い立てても批判にならない
消極的批判については、アプリケーションハンガリアンすべきときと システムハンガリアンすべきときが
区別できない香具師の的外れな批判がクソウゼーからそうなったのかもしれん、
(ちな両者を区別できない香具師への警戒も>>204で言及済み >>214
十分賢いIDEが人間のミスを完璧に排除してくれるんならそうかもしれんが
システムハンガリアンをしてはいけないという積極的理由にはやはりならないのであった
それとも「間違ったコードは間違って見えるようにする 」(>>185)の効能を全否定する?
APIの定義は変わらなくとも、それを利用するソースコードがころころ変わり得るわけで、
byStrLength
にある日だれかがDWORD型の値を突っ込んだとしたら…
こういうケースを考えたら、「接頭辞を見ればデータ内容の属性がワカルというメリット(>>185)」は
ありえないぐらい賢いIDEでも使わないと他に代え難いと思うがどうか、
>>198
>嫌いだからハンガリアン意地でも使わなかった
おk ようやく建設的な議論に着手できる、 あり得ないくらいバカなプログラマのことなんか考慮してない マウスオーバーで変数の型を確認できたり、縮小変換に警告を出してくれたりする程度のありふれた機能が、ありえないぐらい賢いとな
お前さんはメモ帳でコーディングしてるのか >>220
emacs にもそんな機能がほしいと思うことがあります システムハンガリアンでミスを減らせるなんて事はない
むしろ害悪 >>221
俺のemacsには搭載されてるんだが
環境構築もプログラマの腕のうちだからな >>221
有るよ。
irony-eldoc や company-mode を入れろよ。
Emacs こそ最強の IDE だろうが。 今時システムハンガリアンを使うやつはあり得ないくらいのバカだということが決定しました >>218
間違ったコードは間違ったように見えるようにする、について、
あなたが指し示した引用元が言及してるのはアプリケーションハンガリアンについてなんだけど…
システムハンガリアンについては否定的意見。
ちゃんと読んだの? >>223 >>224
thanks a lot!! >>218
APIの仮引数にシステムハンガリアンをつけたことで、間違ったAPI呼び出しが間違ったように見えるのはいつ?
APIのリファレンスなり宣言文なりを自分のコードと見比べたときでしょ?その時必ず型情報も見てるよね?情報重複してるよ?
あとIDEが自動でミスを排除してくれるなんて書いてないよ?ちゃんと読んで ■ このスレッドは過去ログ倉庫に格納されています