トップページ⇒tech
1001コメント275KB

C++相談室 part85

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2010/10/09(土) 20:22:35
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレに
お願いします。

前スレ
C++相談室 part84
http://hibari.2ch.net/test/read.cgi/tech/1284736187/
0653デフォルトの名無しさん2010/10/29(金) 02:03:20
調べるべきは代入でなくて複製構築の方では?
0654デフォルトの名無しさん2010/10/29(金) 02:23:49
>>652 8.5 Initializers
0655デフォルトの名無しさん2010/10/29(金) 03:38:45
ローカル変数としての構築が可能で、かつデストラクタの明示的呼び出しのできない
クラスは定義できますか?
0656デフォルトの名無しさん2010/10/29(金) 03:49:04
デストラクタをprivateに入れる
0657デフォルトの名無しさん2010/10/29(金) 04:10:23
>>655 class { ... } c;
0658デフォルトの名無しさん2010/10/29(金) 08:36:16
アブストラクトファクトリーのテンプレート版みたいな
パターンありますか?
0659デフォルトの名無しさん2010/10/29(金) 11:40:37
それ、パターンじゃなくて実装でしょ。できると思うよ。
0660デフォルトの名無しさん2010/10/29(金) 15:53:21
タブ区切りのデータを出力するプログラムを書きました。【ソース1参照】
しかしヘッダ行[1]とデータの出力行[2]が離れているので、
出力したい項目の追加削除など変更があった場合に
[1]と[2]の2箇所の変更が必要になり、出力項目が多い時はメンテナンスが大変です。

そこで以下のようなクラスを作って楽に管理しようと思いました。【ソース2参照】

使うときはこうします。【ソース3参照】
でも、print_dataというメソッドを実装することって非常に非常に難しいです。
ラムダ式の変数のキャプチャ(?)とかリフレクション(?)とか
マクロをうまく使うとかなんとかして
実現することはできませんか?
同等のことが可能な、スーパープログラマによって書かれたライブラリは存在しませんか?
VC10とgcc4.4で使えるならC++0xの機能や独自拡張を使っていてもかまいません。

疑似コード→ http://codepad.org/Z0j4VE1u
0661デフォルトの名無しさん2010/10/29(金) 16:13:43
かなりアレだな
0662デフォルトの名無しさん2010/10/29(金) 16:50:25
スーパープログラマーってIPA認定のやつか
かなりレアだな
0663デフォルトの名無しさん2010/10/29(金) 16:52:30
目立ったことすればスーパーなんだね
0664デフォルトの名無しさん2010/10/29(金) 17:19:22
>>660
取り敢えず、こんなのどう?
http://codepad.org/ZMJP9HtC
ヘッダの数だけきっかりprint_data()を呼ぶって言う制約がつくけど。
0665デフォルトの名無しさん2010/10/29(金) 21:54:31
テストしてないけど、C++0xの機能とboostでこんなのでどう?

vector<pair<string,function<string()> vec;

int a;
double b;

vec.push_back(make_pair("a",[&](){return boost::lexical_cast<string>(a);}));
vec.push_back(make_pair("b",[&](){return boost::lexical_cast<string>(b);}));

coust<<vec[0].first<<vec[0].second()<<endl;
coust<<vec[1].first<<vec[1].second()<<endl;

0666デフォルトの名無しさん2010/10/29(金) 22:10:13
#include <iostream>

struct Foo
{
template<typename T>
Foo& operator<<(const T& rhs)
{
std::cout << rhs;
return *this;
}
} foo;

int main()
{
foo << 1 << "test";
foo << std::endl; // error: no match for ‘operator<<’ in ‘foo << std::endl’
return 0;
}

これ、何でですか?
0667デフォルトの名無しさん2010/10/29(金) 22:23:03
>>666
endl のテンプレート実引数が不明
0668デフォルトの名無しさん2010/10/29(金) 22:31:18
endlは実は関数で色々オーバーロードされてる
だからTが曖昧になっちゃう
0669デフォルトの名無しさん2010/10/29(金) 22:41:34
こんな感じで明示的に書くと良い
http://codepad.org/KH5rpOc8
0670デフォルトの名無しさん2010/10/29(金) 22:52:39
>>667-669
ありがとうございます。
試しにdecltype(std::endl)とかやってみるとやっぱりerror: ‘std::endl’ refers to a set of overloaded functionsと怒られますね。

>>669
> std::ostream& (*ENDL)(std::ostream& os)
std::ostream& (&ENDL)(std::ostream& os)
でもよいですよね?(実際に試してみてコンパイルエラーは出てないのですが)
インライン化されるか気になって関数のポインタ取るのに抵抗ありまして。
(実際はその程度は関係ないですか?)
0671デフォルトの名無しさん2010/10/29(金) 23:30:25
>>660
凝ったテキスト処理とかやらんからセオリーは知らないけど
ヘッダとやらの項目ごとにデータを溜めてから
一気に書き出した方がいいんじゃないのか?
0672デフォルトの名無しさん2010/10/30(土) 00:00:04
ちょっと質問です。
入門書などのクラスの説明で、よく FILE* のラッパークラス CFile があると思います。

class CFile
{
0673デフォルトの名無しさん2010/10/30(土) 00:01:43
} unko;
0674デフォルトの名無しさん2010/10/30(土) 00:04:14
>>666-670
話が高度すぎてついて行けなかった
手元の「C++再考」を読みながら勉強します
0675デフォルトの名無しさん2010/10/30(土) 00:11:33
途中で送信してしまいました…。

ちょっと質問です。
入門書などのクラスの説明で、よく FILE* のラッパークラス CFile があると思います。

class CFile
{
public:
 bool open();
 bool close();
private:
 FILE* m_fp;
};

コンストラクタで m_fp を初期化し、
デストラクタで m_fp が有効なら fclose でファイルを閉じています。

よくある例ですが、これ、std::vector に入れれないですよね…。
resize でサイズを増やすだけで、一時オブジェクトのデストラクタが走って
予期せずファイルが close されてしまいます。

解決するには参照カウンタを用意し、
コピーコンストラクタなどを適切に書く必要があると思いますが、
特に Windows なら HWND、HFONT、HBITMAP、など
ハンドルのラッパークラス全てに同じ問題がおきます。

どのように解決するのが普通なのでしょうか?
全てに参照カウンタを準備して管理しなければいけないのでしょうか。
すればいいと言われればその通りなのですが、上記クラスに対して「std::vector には入れれない」という解説が見つからなかったので、
誰もが通りそうな問題なのにおかしいなと思って質問です。よろしくお願いします。
0676デフォルトの名無しさん2010/10/30(土) 00:25:46
vector<shared_ptr<CFile> > が普通かな
0677デフォルトの名無しさん2010/10/30(土) 00:26:59
vector オブジェクトを参照かポインタで扱うことにし、コピーしない

配列のコピーを避けることこそ誰もが通る問題で
C をやらないネイティブ C++ 世代の感覚が異様に見える
0678デフォルトの名無しさん2010/10/30(土) 00:28:38
見識を広げてからまたおいで
0679デフォルトの名無しさん2010/10/30(土) 00:31:01
ぶっちゃけ
通常のコンストラクタの他に
CFile():m_fp(NULL){}
みたいなデフォルトコンストラクタを作っといて
デストラクタで
if(m_fp)fclose(m_fp);
ってやれば当面の問題は解決されるんじゃないの?
0680デフォルトの名無しさん2010/10/30(土) 00:37:16
>>679
解決されるわけないだろバカ
0681デフォルトの名無しさん2010/10/30(土) 00:39:41
俺みたいなバカにはよくわかんないな。
どうしてvectorに入れたいんだろう?
vector<shared_ptr<CFile>>だと明示的にクローズしないとクローズされなくなるような…
それとも使う度にvectorからは抜くとか、vectorごと捨ててまとめてクローズしたいとかそういうことなの?
0682デフォルトの名無しさん2010/10/30(土) 00:46:27
boost::ptr_vector<CFile*>でもいいな
0683デフォルトの名無しさん2010/10/30(土) 00:49:33
>>681
読解力の低さと思考停止の早さがひどすぎて回答が難しいよ
もう少し頑張れよ
06846752010/10/30(土) 00:51:42
>>676-677
C のころはデストラクタもないし、malloc / realloc で何も問題なかったんですよね…。
vector<shared_ptr<CFile> > で解決できそうです。
RAII の解説のところで、コピーコンストラクタなどを private にして
コピーを防いでいる例も見つけましたので、合わせて使おうと思います。
ありがとうございました!
0685デフォルトの名無しさん2010/10/30(土) 00:55:08
>>683
いやどういうときに使うものなのか見当がつかないだけだよ
06866752010/10/30(土) 00:55:56
>>682
ptr_vector!
これを忘れていました。是非使ってみようと思います。こちらもありがとうございました。
0687デフォルトの名無しさん2010/10/30(土) 00:56:29
>>684
FILE*だもんな・・・
0688デフォルトの名無しさん2010/10/30(土) 00:59:21
>>686
ゴメン
やっぱboost::ptr_vector駄目だわ
これresizeするとポインタを通してデストラクタを呼ぶためのコンテナなんだよね
だからこの場合は駄目だと思う
0689デフォルトの名無しさん2010/10/30(土) 01:33:47
悪い、ビール買いに行っていて遅くなった
要するにこういう感じで勝手にデストラクタが呼ばれるといけないわけだよね?

#include <iostream>
#include <boost/ptr_container/ptr_vector.hpp>
class Test {
int i;
public:
Test(int j) : i(j) {}
~Test() { std::cout << "~Test(" << i << ") is called" << std::endl; }
};
int main()
{
boost::ptr_vector<Test> ptt;
for (int i = 0; i < 10; i++)
ptt.push_back(new Test(i));
boost::ptr_vector<Test>().swap(ptt);
std::cout << "Excecution done" << std::endl;
}

~Test(0) is called
~Test(1) is called
~Test(2) is called
~Test(3) is called
~Test(4) is called
~Test(5) is called
~Test(6) is called
~Test(7) is called
~Test(8) is called
~Test(9) is called
Excecution done
0690デフォルトの名無しさん2010/10/30(土) 01:35:14
>>677
vector を参照かポインタで扱っても、もともとの問題である vector に CFile を入れる段階の
問題が何も解決しない。

配列のコピーが行われたところで十分な空間・計算リソースがあれば問題にならないんで、
誰もが通る問題とも思えない。
0691デフォルトの名無しさん2010/10/30(土) 01:36:14
>>688
何も問題ないように見えるが、何がダメだって言うの?
06926852010/10/30(土) 01:43:44
うーん考えたけどまるで思いつかないよ。

ちょくちょく出し入れしないとsharedする意味がないし、vectorにそれが向いてるとは思えない。
コンテナに入れる用途だとselectポーリングするとか、サーバー側のソケット/パイプ管理や
クライアント側のコネクションプールのようなものとかだけど、ポーリング以外では切断する役割
よりも使用未使用管理になると思うし、ポーリングを使うような状況でvectorは俺なら使わない。
そもそも面倒なのでポーリングしないで一個ずつスレッド使っちゃうし。

誰かvector<shared_ptr<CFile>>の利用用途を教えてくれー。
0693デフォルトの名無しさん2010/10/30(土) 01:50:02
>>691
いやいやだからpush_backしていくうちにメモリの再配置が起きてその時に
勝手にデストラクタが呼ばれてファイルストリームがクローズしちゃうじゃん

それを嫌がってるんでしょ?

自分でデストラクタを呼び出すならstd::vector<CFile*>でも何の問題もないような気がするんだけど
0694デフォルトの名無しさん2010/10/30(土) 01:51:56
>>692
shared_ptr が使われてるのは、単に C++2003 にはムーブや unique_ptr が無いからでしょ。
出し入れがしたいわけじゃないと思うよ。

「〜ような状況でvectorは俺なら使わない」と言うけど、それこそ理由が不明。

単に CFile の配列が欲しくて、実行時にしか要素数が決まらないってだけで十分でしょ。
0695デフォルトの名無しさん2010/10/30(土) 01:56:02
>>694
素人考えだとならlistではダメなの?って思うのですよ
利用用途が思いつかないからいいのかどうか見当もつかないんですけど
0696デフォルトの名無しさん2010/10/30(土) 01:56:40
>>695
単にoperator[]を使いたいんだと思うよ
06976752010/10/30(土) 01:59:35
何か話が入れ込んでしまってすみません。

>いやいやだからpush_backしていくうちにメモリの再配置が起きてその時に
>勝手にデストラクタが呼ばれてファイルストリームがクローズしちゃうじゃん

まさにこれです。

vector<CFile> files;
files.resize(1);
files.resize(2); // ←ここでメモリの再配置がおきて、files[0] のデストラクタでファイルが閉じられるので困る

CFile の配列を使うことはあまりないかもしれませんが、
可変個のウィンドウを扱う(HWND)、ビットマップを扱う(HBITMAP)、などはよくあると思います。
>>692 で1個ずつスレッドにしても、スレッドを管理する HANDLE を持つクラスの可変長配列が必要です。
0698デフォルトの名無しさん2010/10/30(土) 02:00:40
>>693
何のための ptr_vector だよ。

ptr_vector なら再確保が発生してもポインタのコピーだけすればよくて、
オブジェクト本体のコピーが要らない。したがってデストラクタが呼ばれたりもしない。

自分でデストラクタを呼び出すなんて、論外だね。
0699デフォルトの名無しさん2010/10/30(土) 02:06:14
0x の移動に対応したコンパイラなら vector<fstream> で良さそうだが
0700デフォルトの名無しさん2010/10/30(土) 02:07:29
あーそうですね
0701デフォルトの名無しさん2010/10/30(土) 02:10:21
>>698
それはわかってる
でも今回のように勝手にデストラクタが呼ばれては困るファイルストリームインスタンスへの
ポインタを保持する場合は駄目でしょって
0702デフォルトの名無しさん2010/10/30(土) 02:12:46
>>701 >>691
0703デフォルトの名無しさん2010/10/30(土) 02:16:31
>>696
なるほどまづは前提として受け入れろと
>>697
なるほど。リソースハンドル全般の話で使いまわしとは関係がない話なのですね。
オブジェクトとリソースの生成/消滅は原則連動してて、未参照状態で自動的に
消滅さ&コンテナはとにかくvectorがいいと。

0xはまだまだ知らないことだらけだけど、なんか面白そうですね。
0704デフォルトの名無しさん2010/10/30(土) 02:21:19
>>702
>>689にこれじゃ駄目でしょうって例をわざわざ貼り付けたんだけど理解できないかな?
0705デフォルトの名無しさん2010/10/30(土) 02:31:12
>>704
テンポラリに swap() で内容を移してるんだから、そのテンポラリの消滅で
デストラクタが走って当然。これを「勝手に」とか言ってるのがどういうことなのか
理解できない。
0706デフォルトの名無しさん2010/10/30(土) 02:37:08
>>705
いやだから・・・std::vectorでpush_backして行くとそのうち連続したエリアが足りなく
なってメモリの再配置が起きるでしょうって

boost::ptr_vectorも事情は同じですよって言う意味で書いたんだけど分かってもらえないかな?
0707デフォルトの名無しさん2010/10/30(土) 02:46:41
>>706 >>698
0708デフォルトの名無しさん2010/10/30(土) 02:48:16
>>707
外行って頭に水ぶっかけて来い
0709デフォルトの名無しさん2010/10/30(土) 02:50:18
再配置結果
http://ideone.com/C0UYF

capacity() == size()はcapacity()が満たされた場合であり、再配置が起こる
明示的にresize()も呼び出してみた
再配置が起こってもデストラクタは起動しない
スコープアウトしてはじめてデストラクタが起動する
0710デフォルトの名無しさん2010/10/30(土) 02:52:21
http://codepad.org/3PHDRO8v
おっと。似たようなことしてる人が・・・
0711デフォルトの名無しさん2010/10/30(土) 02:53:38
アホをいち早く切り捨てた >>683 カコイイ
0712デフォルトの名無しさん2010/10/30(土) 03:00:01
今頃頭に水かぶりにいったのかな?
0713デフォルトの名無しさん2010/10/30(土) 03:04:27
うわぁ・・・
0714デフォルトの名無しさん2010/10/30(土) 03:05:56
夜中に元気だなお前ら
0715デフォルトの名無しさん2010/10/30(土) 03:18:20
金曜日の夜だけは元気なんだよ
0716デフォルトの名無しさん2010/10/30(土) 03:19:55
・メモリの再配置が起きてもデストラクタは起動しない
・但しイテレータは無効になる

か
0717デフォルトの名無しさん2010/10/30(土) 03:28:21
>>716
あくまでポインタを保持している場合の話な

>>709のコード貼っといて言うのもアレだが
オレはコンテナにファイル管理クラスを突っ込んだりしないけどな
入れるとしたらファイル名とかリソースバッファか
ファイル処理なんてエラーが出やすいし、アクセスは単純化してわかりやすい方がいい
こんな論争現場でしたくないだろw
0718デフォルトの名無しさん2010/10/30(土) 03:31:42
つまり今回のようなケースではboost::ptr_vectorで問題はないわけだ
0719デフォルトの名無しさん2010/10/30(土) 09:58:53
>>697
CFileってコピー可なのか?普通はコピー不可にするべきだろう。MFCって一体?

コピー不可でも、C++0xならムーブ可にしておけばvectorに入るだろうし、突然閉じたりしないしな
0720デフォルトの名無しさん2010/10/30(土) 10:39:12
MFCの話してるわけじゃないだろ
それにMFCのCFileはコピー不可だよ
0721デフォルトの名無しさん2010/10/30(土) 13:15:33
>>697
list じゃだめなん?
HWND なんか典型的にリストの出番だと思うし
それ以前に EnumWindows だろ

vector に push_back を多用する時点で何かおかしいと思わないのか?
resize で不具合が出るのをわかっていて resize にこだわる時点で何かおかしいと思わないのか?

ちなみに MFC は RTTI や文字列を自前で作っているが、それがどういう意味かわかる?
0722デフォルトの名無しさん2010/10/30(土) 13:51:21
set<int> s; // あるいはlistやvector

// ・・・・

set<int>::iterator it = s.begin(), end = s.end();

while(it != end)
{
DoSometing(s, *it);
++it;
}

DoSometingでコンテナの要素が増減する可能性がある場合ってイテレーターは無効になりますか?
0723デフォルトの名無しさん2010/10/30(土) 13:57:45
うん
0724デフォルトの名無しさん2010/10/30(土) 14:56:48
>>722
itがさしている要素が削除されるとitが無効になるよ。
0725デフォルトの名無しさん2010/10/30(土) 15:08:37
        ____
       / \  /\ キリッ
.     / (ー)  (ー)\
    /   ⌒(__人__)⌒ \   <HWND なんか典型的にリストの出番だと思うし
    |      |r┬-|    |        それ以前に EnumWindows だろ
     \     `ー'´   /

        ____
       / \  /\ キリッ
.    +/ (●)  (●)\
    /   ⌒(__人__)⌒ \+   
    |              |  クスクス>
     \            /

        ____
<クスクス   / \  /\ キリッ
.     / (●)  (●)\
    /   ⌒(__人__)⌒ \ +  
    |              |        
   + \            /
0726デフォルトの名無しさん2010/10/30(土) 15:15:11
許してやれよ
0727デフォルトの名無しさん2010/10/30(土) 15:18:31
vector に push_back を多用するのは何がおかしいの?
0728デフォルトの名無しさん2010/10/30(土) 15:21:59
効率がおかしい
0729デフォルトの名無しさん2010/10/30(土) 15:24:33
そういう効率だけを考えていてもダメ
ダメプログラマーになりたいのなら別だがな
0730デフォルトの名無しさん2010/10/30(土) 15:24:45
reserve()しとけば問題ないんじゃないの
0731デフォルトの名無しさん2010/10/30(土) 15:25:29
規格どおりならおかしくもなんともない。
0732デフォルトの名無しさん2010/10/30(土) 15:27:06
そういう規格だけを考えていてもダメ
ダメプログラマーになりたいのなら別だがな
0733デフォルトの名無しさん2010/10/30(土) 15:28:45
vectorでreserveしてpush_backするぐらいならdeque使っておけて事?
0734デフォルトの名無しさん2010/10/30(土) 15:33:39
dequeじゃ同じことなんじゃ…
0735デフォルトの名無しさん2010/10/30(土) 15:35:38
EnumWindowsはどっから出てきたんだ
0736デフォルトの名無しさん2010/10/30(土) 15:37:31
許してやれよ
0737デフォルトの名無しさん2010/10/30(土) 15:42:00
確かにEnumWindowsは出てくるべきではないと思うね
そういえばこれのコールバックをコルーチンでiterateする面白い実装をどっかで見たな
0738デフォルトの名無しさん2010/10/30(土) 15:44:21
許すって何を?
空笑がみられる病人がいるようだが
許したければ許せばいいだろ自分で
0739デフォルトの名無しさん2010/10/30(土) 15:54:40
意味のない一言煽り多いよな。それしかできなそうって感じもするけど。
0740デフォルトの名無しさん2010/10/30(土) 15:56:22
>>739
自分に言ってるのか
0741デフォルトの名無しさん2010/10/30(土) 16:02:26
>>740
いや、素直な感想を言ってるだけ
0742デフォルトの名無しさん2010/10/30(土) 16:04:31
言ってる自分が気づいてないんだな。
0743デフォルトの名無しさん2010/10/30(土) 16:15:39
図星だったのか
0744デフォルトの名無しさん2010/10/30(土) 16:18:57
>>743
意味のない一言煽り多いよな。それしかできなそうって感じもするけど。
0745デフォルトの名無しさん2010/10/30(土) 16:43:14
君たち、 C++ の話をしろ
0746デフォルトの名無しさん2010/10/30(土) 17:08:21
push_back を多用するな。 push_front を使うんだ(キリッ
0747デフォルトの名無しさん2010/10/30(土) 17:12:29
>>746
vectorでは禁じ手
というかメンバ関数がなかったんじゃないか?
0748デフォルトの名無しさん2010/10/30(土) 17:17:10
つまりInsertを使えってことだな
0749デフォルトの名無しさん2010/10/30(土) 17:18:12
vectorでは禁じ手(キリッ
というかメンバ関数がなかったんじゃないか?(キリッ
0750デフォルトの名無しさん2010/10/30(土) 17:22:15
>>747
許してやれよw
0751デフォルトの名無しさん2010/10/30(土) 17:26:10
ついでに初歩的な質問していい?
vectorの速度的な話で大規模な配列を取り扱う場合

遅い順に

reserveされてない領域へのpush_back
reserveされてる領域へのpush_back
resize等で既に確保されてる領域への代入
vectorを使わない静的配列への代入

って感じであってる?
push_backが遅いのは仕様だよね?
0752デフォルトの名無しさん2010/10/30(土) 17:31:31
resize等で既に確保されてる領域への代入
vectorを使わない静的配列への代入

これは同じじゃないかな
■ このスレッドは過去ログ倉庫に格納されています