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

C++相談室 part54

■ このスレッドは過去ログ倉庫に格納されています
0001v(^・^)v2006/10/30(月) 22:34:08
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE(VC++など)などの使い方の質問はその開発環境のスレに
お願いします。

テンプレその他 >>2-15 付近参照

前スレ
C++相談室 part53
http://pc8.2ch.net/test/read.cgi/tech/1159340181/
0052デフォルトの名無しさん2006/11/02(木) 00:28:04
>>51
オブジェクトが普通に表示されたり、
deleteする前の値(位置情報 xやyなど)
をそのまま持っているかどうかで確認しています。
0053デフォルトの名無しさん2006/11/02(木) 00:29:46
>>48
> enemy = new Enemy1(arg_x, arg_y);
> EnemyArr.push_back(enemy);
原因の予感。push_back(const T&)じゃなかったか。
ゆえに、push_back(new Enemy1(arg_x, arg_y))で試してみて。
0054デフォルトの名無しさん2006/11/02(木) 00:34:07
>>52
それって、破棄したオブジェクトをそのまま使ってるんじゃないか?
erase()でvectorの方も縮めておかないとだめだろ。
0055デフォルトの名無しさん2006/11/02(木) 00:34:33
>>52
deleteしたからって中のデータは直ぐに破壊されん。
そんなん何の参考にならんし確認にもなってない。
0056デフォルトの名無しさん2006/11/02(木) 00:36:15
まあコンテナにポインタだけを入れるのなら、boost::ptr_vectorの方が
使いやすいぞ。erase()したら自動的にdeleteしてくれるしな。
0057デフォルトの名無しさん2006/11/02(木) 00:42:11
ちょっと状態遷移にそって処理を行いたいのですが解らないことがあります。
各個別は古典的にstateパターンで処理可能なルールとして実装できると思いますが
文脈を管理するためのクラスはどのように実現するのが一般的なのでしょうか?
ルールはR0 = Aから始まるとします。

A = B | C
B = a b c
C = a | b c
a = ...
b = ...

StateパターンでR0の状態を処理する。
0058デフォルトの名無しさん2006/11/02(木) 00:42:59
deleteしてもそのポインタの指してる先が0でクリアされるわけじゃないから
ポインタが指してる部分に情報が残ってるだけでは?
デストラクタにstd::cout << "Delete Enemy" << std::endl;って行を入れて動作を確認してみて。
0059デフォルトの名無しさん2006/11/02(木) 00:44:19
>>57が何を言いたいのか全然わからない
0060デフォルトの名無しさん2006/11/02(木) 00:45:17
>>54,55
成る程、そういうことでしたか。
eraseする前に破棄されてるか確認したかったのですが、
それでは意味がないですね。

>>53
結局破棄されてないと勘違いしただけだったみたいですが、
その記述で一時的な変数が必要なくなって助かりました。

>>56
そういう便利なものもあるんですね。
ちょっと調べてみたいと思います。

>>58
成る程、デストラクタに入れておけば破棄された確認になりますね。
やってみます。
0061デフォルトの名無しさん2006/11/02(木) 00:50:43
自分で書いてて意味不明だな。
とりあえず、文法を解析するときに
個別のルールはStateパターンで処理したいけど
文脈はどうやって処理すればいいのか思いつかないから助けて
ほしいだけかもしれない
0062デフォルトの名無しさん2006/11/02(木) 00:53:03
vectorにポインタを入れておいて、deleteした後その要素を使いたく
ないなら、0を代入しておく方法もある。vectorコンテナは要素数が
大きくなると、eraseにO(N)かかるので高くつく。そこでdeleteした要素
には0を入れておき、後で必要になったらまず0の入っている要素を
再利用するという方法もある。

もちろんプログラム側で要素に0が入っていたら処理をスキップする
必要があるが。
0063デフォルトの名無しさん2006/11/02(木) 00:54:59
>>61
まずデザパタに頼らず強引に文法解析の骨子を書いてみたら。
その後でStateパターンでまとめると綺麗にまとまるというだけの話。
0064532006/11/02(木) 00:56:07
>>60
ごめん俺が間違ってた。気にするな。
>EnemyObj*       enemy;
もちろんvirtualなデストラクタを持たせてるよね
0065デフォルトの名無しさん2006/11/02(木) 01:03:50
>>53
push_back(new ...) はあからさまに例外安全じゃないので考え直したほうがいい。
0066デフォルトの名無しさん2006/11/02(木) 01:20:55
>>58
破棄の確認が取れました。
ちゃんと破棄できていたようです。有難う御座います。

>>62
成る程、そういった利用方法もできるのですかぁ。
勉強になります。

>>64
持たせて破棄の確認をしました。
お騒がせしました。

>>65
それは
push_back(new ...)
にするより、元のコードのままの方がいいということですか?
0067デフォルトの名無しさん2006/11/02(木) 01:27:11
newが例外を投げる可能性があるからね。
コンテナに対する操作とは分離しておいた方がいいだろう。

それと、コンテナの要素にアクセスする方法が単なるラウンドロビン的な
方法のみで、ランダムアクセスをしないのであればstd::listの採用を考え
るのもよい。こちらはeraseしても反復子が無効にならない上、常にコストは
O(1)だから。
0068デフォルトの名無しさん2006/11/02(木) 01:27:12
>>47
new に対応する operator new はクラスのメンバとして宣言されたものか、
グローバルなものかのどちらかになる。 (5.3.4 9)
0069デフォルトの名無しさん2006/11/02(木) 01:28:15
>>67
問題は push_back() が例外を投げた場合なわけだが。
0070デフォルトの名無しさん2006/11/02(木) 01:29:52
>>66
元のコードも多分例外安全じゃない(いや、まcatchで適切にリソースの解体しているなら別だけど)

auto_ptr<Enemy>enemy(new Enemy(..));
EnemyAry.push_back(enemy.get());
enemy.release();

だいたいこんな感じで書けば例外安全。
0071デフォルトの名無しさん2006/11/02(木) 01:32:33
>>70
ちょwwwwそれやり過ぎww
まあ業務用ソフトならそこまでするのかもしれんけど
0072デフォルトの名無しさん2006/11/02(木) 01:40:29
>>67,70
うーむ、まだまだ未熟で理解できない点がありますので、
これから習熟していく上で徐々に理解していきたいと思います。
有難う御座いました。
0073デフォルトの名無しさん2006/11/02(木) 01:42:36
>>70は別にやりすぎとは思わないな
これくらいがふつう
0074デフォルトの名無しさん2006/11/02(木) 01:45:22
だよな。
いつの日か、こんなのがリークの原因になってしまったとしたら、見つける自信が無い。
最初に書くときに安全を確保してしまうのが吉。
0075デフォルトの名無しさん2006/11/02(木) 01:47:45
>>70
これって、もしEnemyAryがptr_vectorだったら例外安全難しくない?
1.
auto_ptr<Enemy>enemy(new Enemy(..));
EnemyAry.push_back(enemy.get());
enemy.release();
→enemy.release()が例外を投げるとptr_vectorとauto_ptrによる二重delete
2.
auto_ptr<Enemy>enemy(new Enemy(..));
EnemyAry.push_back(enemy.release());
→push_backが例外を投げるとリーク
0076デフォルトの名無しさん2006/11/02(木) 01:51:02
>>75
releaseは例外を投げなーい。
だから安心安心。
0077デフォルトの名無しさん2006/11/02(木) 01:58:46
>>75
prt_vector なら push_back(new ...) でいいだろ。 >>70 みたいな
コーディングを不要にするためのものなんだから。
0078デフォルトの名無しさん2006/11/02(木) 02:03:00
push_backが例外投げたらどうすんだよ!
0079デフォルトの名無しさん2006/11/02(木) 02:08:32
push_backって例外投げたっけ?
0080デフォルトの名無しさん2006/11/02(木) 02:08:38
>75
auto_ptr::release()は例外投げません……
0081デフォルトの名無しさん2006/11/02(木) 02:10:45
>>79
少なくともバッファが確保出来ないときは投げるんじゃない?
0082デフォルトの名無しさん2006/11/02(木) 02:11:44
>>79
配列の拡張時にメモリ確保失敗する可能性があるから投げると思うよ。
ちょっとソース見てくる。
0083822006/11/02(木) 02:21:02
見てきた。
>>77のいうようにptr_*系は直接push_back呼び出して問題ない。
というか内部でauto_ptrつかって実質的に>>70と同じ処理をやってる。
だから、むしろauto_ptr使うと例外時に2重開放になるから使っちゃ駄目。

例外発生時にはpush_backは何もしないと思ってたので、
勝手に引数の開放するのは予想外だったのでちょっと驚き。

これからはptr_*系をちょくちょく使っていくか......
0084デフォルトの名無しさん2006/11/02(木) 02:23:11
うげ、勝手に引数の状態変えるのかよ・・・
0085デフォルトの名無しさん2006/11/02(木) 02:29:03
そういえば、失敗したときに勝手に delete するんなら Strong guarantee とは
言えないな。

あれー?
http://www.boost.org/libs/ptr_container/doc/ptr_sequence_adapter.html#modifiers
0086デフォルトの名無しさん2006/11/02(木) 02:49:00
質問なんですが、関数の実引数や仮引数に auto_ptr<> を頻繁に使うことってあるんでしょうか?
0087デフォルトの名無しさん2006/11/02(木) 02:53:46
>>86
new したオブジェクトの所有権が関数をまたいで頻繁に移動するならそうなるだろう。
0088デフォルトの名無しさん2006/11/02(木) 03:22:22
>>87

なるほど。忘れていました。そうですよね。所有権が移動するから使えるんですか。
ありがとうございます。
0089デフォルトの名無しさん2006/11/02(木) 03:23:08
そもそもauto_ptrって頻繁に使いますか??

使わんとは言わんが、結局目の届く範囲においとかないと怖くて仕方ないので
エラー処理とかでdeleteまとめんのが面倒くさいとかの時くらいしか出番ないですよ。
叩いて叩いて。
0090デフォルトの名無しさん2006/11/02(木) 03:31:52
リソースリークを防止する一番簡単な方法がauto_ptr
0091デフォルトの名無しさん2006/11/02(木) 03:43:15
自前でdeleteする手間とほとんど変わらん、便利よりも不便のが増えるで、
あればあったで構わないけど積極的な使用を推奨する気にはなれん代物でFA。
0092デフォルトの名無しさん2006/11/02(木) 03:46:02
>>89
new があるところに auto_ptr あり。少なくとも new と同じぐらい使う。
boost 使ってるときは、ほとんどそっちになるけど。
0093デフォルトの名無しさん2006/11/02(木) 03:46:45
>>91
auto_ptr で増える不便って何?
0094デフォルトの名無しさん2006/11/02(木) 04:00:22
>>91
手動deleteで例外安全確保しようと思ったらauto_ptrの100倍は面倒だろ
0095デフォルトの名無しさん2006/11/02(木) 04:08:20
例外安全性なんて知ったことじゃありまっせん!
0096デフォルトの名無しさん2006/11/02(木) 06:42:13
例外発生時点でそこから先計算不能な状態なんで書き込みリソースくらいしか例外安全に気を遣わない。
つか例外でたらabortせざるをえない。
0097デフォルトの名無しさん2006/11/02(木) 09:30:17
>>68
遅くなりました。
ネームスペースに入れるとクラスのメンバのような扱いになっているって事ですか??
もう少しヒントを・・・
0098デフォルトの名無しさん2006/11/02(木) 10:44:22
>>96
あー、よく聞くな。そのいいわけ。
0099デフォルトの名無しさん2006/11/02(木) 10:45:53
>>97
new を使ったときにメモリ確保に使われる operator new の決定方法は規格で
決められているわけだが、(以下 >>68 )
0100デフォルトの名無しさん2006/11/02(木) 12:17:19
>>96
始皇帝氏って奴?
0101デフォルトの名無しさん2006/11/02(木) 15:17:56
template<class T> class Test
{
vector<T> array;
public:
vector<class T>::iterator getBeginIterator()
{
return array.begin();
}
};

こんなクラスを作ったのですが
main関数で
Test<unsigned char> test1;
vector<unsigned char>::iterator itr = test1.getBeginIterator();
とすると
main.cpp(37) : error C2440: '初期化中' : 'std::vector<_Ty>::iterator' から 'std::vector<_Ty>::iterator' に変換できません。
というエラーがでます。
どなたか原因がわかりませんか?
0102デフォルトの名無しさん2006/11/02(木) 15:26:26
>vector<class T>::iterator getBeginIterator()
typename std::vector<T>::iterator getBeginIterator()
0103デフォルトの名無しさん2006/11/02(木) 15:27:00
>>101
Tというclassとclass Tという先行宣言の差。
vector<class T>をvector<T>にすれば多分大丈夫
0104デフォルトの名無しさん2006/11/02(木) 15:50:06
>>83
push_back前の状態にロールバックするのが強い例外保証だからそれでいいんだよ。ていうか開放しないとリークしちゃうし。

newの戻り値をどっかに保存してたりするならそれはユーザー側の使い方が間違い。

abortするしかないとか言ってるやつは例外機構をメモリリーク防止くらいにしか思ってないんだろうなぁ。
0105デフォルトの名無しさん2006/11/02(木) 16:05:08
リークを防ぐために例外発生時にも、
引数のオブジェクトの所有権を奪うという副作用を行っているんでしょ?
その副作用のロールバックが出来ていないと思うけど、俺の解釈の仕方が間違っている?

いや、ま、利便性考えればこの仕様が自然なんだけどね。
例外時にいちいち開放したくないし。
0106デフォルトの名無しさん2006/11/02(木) 16:09:58
いや、コンテナにポインタを入れるという行為そのものが所有権の委譲なんだよ。
0107デフォルトの名無しさん2006/11/02(木) 16:11:31
すまん。今のなしorz
0108デフォルトの名無しさん2006/11/02(木) 16:17:12
問題は開放しないことにしてしまうと今度は基本的保証がされなくなってしまうことだね。強い保証がされてるかどうかは考え方の問題な気がする。
0109デフォルトの名無しさん2006/11/02(木) 16:22:42
>>98
仮想記憶無い環境だとnewできない時はもうどうしようもねぇんだよ。
0110デフォルトの名無しさん2006/11/02(木) 16:28:14
根本的には、
所有権の移動と配列の拡張という別個の事象を、
一つの関数で行うから、起きる問題だな。

stackのpop,topみたいに綺麗に二つに分けれると良いんだけど、
そもそも二つをくっつける為のptr_vectorというジレンマ
0111デフォルトの名無しさん2006/11/02(木) 16:36:24
int x[3] = {3,5,1};
vector<int> a(&(x[0]), &(a[2]) + 1);
a.sort(not2(less<int>() ) ); //

関数アダプタ not2() を入れた場合、エラーはでないのですが、実行した場合に強制終了となってしまいます。
なぜ、強制終了してしますんでしょうか?
ソフトはVC++EEです。
0112デフォルトの名無しさん2006/11/02(木) 16:37:23
>>111
&(x[0]), &(a[2])+1
 
0113デフォルトの名無しさん2006/11/02(木) 17:00:17
>>112
a(&(x[0]), &(x[2]) + 1);

です。
0114デフォルトの名無しさん2006/11/02(木) 18:20:38
std::vectorのメンバ関数にsortなんてあったっけ?
0115デフォルトの名無しさん2006/11/02(木) 18:24:40
>>114
少なくともうちのVC8には無い。
int x[3] = {3,5,1};
vector<int> a(&(x[0]),&(x[2])+1);
sort(a.begin(),a.end(),not2(less<int>()));//

ちなみにこれなら普通に実行できたが。
どこのvector使ってるんだろう?
0116デフォルトの名無しさん2006/11/02(木) 18:43:31
失礼しました。
listです。
0117デフォルトの名無しさん2006/11/02(木) 19:38:09
>>116
もう信用できない。問題の発生するコードをコピペしろ。
0118デフォルトの名無しさん2006/11/02(木) 19:50:31
#include "stdafx.h"
#include <list>
#include <functional>
#include <iostream>
using namespace std;
template<class InputIterator> void Display(InputIterator first, InputIterator last){
for(InputIterator i = first; i != last; i++)cout << *i << " ";
}
template<class T> struct MyGreater : public binary_function<const T, const T, bool> {
bool operator() (const T &t1, const T &t2) const { return t1 > t2;}
};
void main(){
int a[8] = {5,8,4,2,41,6,9,7};
int b[14] = {9,9,4,2,1,0,5,6,7,1,1,1,1,1};
list<int> lst1(&(a[0]), &(a[7]) + 1);
list<int> lst2(&(b[0]), &(b[13]) + 1);
list<int>::iterator w = lst1.begin();
advance(w, 3); lst1.splice(w, lst2);
Display(lst1.begin(), lst1.end());//3
lst1.sort(); Display(lst1.begin(), lst1.end());//4
lst1.sort(not2(greater<int>() ) );//-------ココです
Display(lst1.begin(), lst1.end());//5
}
0119デフォルトの名無しさん2006/11/02(木) 20:08:02
>>118
試したらデバッグモードのチェックで "invalid operator<" と言われたが、
「強制終了してします」ってのはこれのことか?

not(greater<int>()) つまり <= は比較関数に要求される
strict weak ordering の要件を満たさないってこと。
0120デフォルトの名無しさん2006/11/02(木) 20:15:33
not2(greater_equal<int>()かless<int>()つかえって話だな。
0121デフォルトの名無しさん2006/11/02(木) 20:21:56
>>119
>>120

わかりました!
ありがとうございました。
0122デフォルトの名無しさん2006/11/03(金) 00:19:41
>>99
また遅くなってしまい、スイセン
理解しました。まさしく文章通りでしたね。
確かにnew ヘッダも定義はstdの外でやっていました。
これで納得して進めることが出来ます。どうも有難う御座いました。
0123デフォルトの名無しさん2006/11/03(金) 01:29:51
最近(というより数年前から)C++でもdoSomething()のような
Java風の命名を良く見かけるのですが、何か理由はあるのですか?
0124デフォルトの名無しさん2006/11/03(金) 01:31:10
>>123 名前付けた奴に聞けよ。
0125デフォルトの名無しさん2006/11/03(金) 01:41:46
>>123
バカは氏ね
0126デフォルトの名無しさん2006/11/03(金) 02:12:57
>>123
典型的なところで、XercesみたいにJava出身のライブラリは当然、Java風になるね。
0127デフォルトの名無しさん2006/11/03(金) 03:43:18
>>123
C++風の命名ってどういうものなんでしょう?
JavaからOOPL入ったので良くわかりません...
0128デフォルトの名無しさん2006/11/03(金) 03:48:05
C/C++
class_name
func_name
Java
ClassName
funcName
確かにJavaスタイルをよく見かける。このスレ(板)でも。
0129デフォルトの名無しさん2006/11/03(金) 04:20:34
それをC++風だとか、Java風とか分類するのがナンセンスなんだよ
0130デフォルトの名無しさん2006/11/03(金) 04:48:46
C/C++
fuck_cpp
Java
fuckJava

コーディングスタイルは他でやれよ
0131デフォルトの名無しさん2006/11/03(金) 05:14:52
確かに、最近WindowsAPI風の関数名をよく見るね
0132デフォルトの名無しさん2006/11/03(金) 05:21:23
それはDoSomething()
まあ、どうでもいいけどね
01331012006/11/03(金) 09:24:27
>>102, >>103 サンクス。
>typename std::vector<T>::iterator getBeginIterator()
でいけました。
0134デフォルトの名無しさん2006/11/03(金) 09:34:13
仮の型指定のあるテンプレート前方宣言はどう宣言したらいいのでしょうか?
仮の型指定がない次のような場合は通るのですが
template < typename _T > class A; // 前方宣言
typedef A< int > B;
template < typename _T > class A // 定義
{
};

main( void )
{
B b;
}

以下のケースのように定義側に仮の型指定がある場合の前方宣言の仕方がわかりません。

template < typename _T = int > class A; // 前方宣言 無理 ERROR
// template < typename _T > class A; // 前方宣言 無理 ERROR
// template < > class A; // 前方宣言 無理 ERROR

typedef A< > B;
template < typename _T = int > class A // 定義
{
};

main( void )
{
B b;
}
0135デフォルトの名無しさん2006/11/03(金) 09:55:10
>>93
> auto_ptr で増える不便って何?

頭悪い子が付いていけない。
0136デフォルトの名無しさん2006/11/03(金) 10:37:34
templateの機能を1から学ぼうと思うとどれ読めばいいの?
Moden C++とか読むと書いてあることは解るけどなんでそんなこと
思いつくのよこの変態とか思うわけで....
0137デフォルトの名無しさん2006/11/03(金) 10:39:28
書いてあることが分かるなら一から学ぶ必要は無い。
0138デフォルトの名無しさん2006/11/03(金) 10:57:52
>>137
いやそれだと狭い知識しかみにつかんからもし
機能を体系的に勉強できるような資料があればうれしいのよ
0139デフォルトの名無しさん2006/11/03(金) 11:02:23
>>138
lisp, Haskell, etc,,
0140デフォルトの名無しさん2006/11/03(金) 11:07:13
>>136
機能を学ぶ以前に、想像力(or創造力)を鍛えた方が医院で内科医?
0141デフォルトの名無しさん2006/11/03(金) 11:16:17
>>136
もう読んでいるのかもしれないけど、
>>4のC++ Templates
0142デフォルトの名無しさん2006/11/03(金) 12:11:56
このtemplateが永遠にコンパイルできません。助けてください

template<int Depth, int A, typename B>
struct K17 {
static const int x =
K17<Depth+1, 0, K17<Depth,A,B> >::x
+ K17<Depth+1, 1, K17<Depth,A,B> >::x
+ K17<Depth+1, 2, K17<Depth,A,B> >::x
+ K17<Depth+1, 3, K17<Depth,A,B> >::x
+ K17<Depth+1, 4, K17<Depth,A,B> >::x;
};
template<int A, typename B>
struct K17<16,A,B> {
static const int x = 1;
};
static const int z = K17<0,0,int>::x;
0143デフォルトの名無しさん2006/11/03(金) 12:16:47
K17<Depth,A,B>の中にK17<Depth+1, 0, K17<Depth,A,B> >::x があると
その実体化にまたK17<Depth,A,B>が必要になるから
struct A{ A a;};と同じことになるんじゃね?
0144デフォルトの名無しさん2006/11/03(金) 12:16:58
内部構造がスッタクオーバーフローしましたとかいう
意味不明なエラーが出て困ってます。
0145デフォルトの名無しさん2006/11/03(金) 12:22:06
たった7600億回インスタンス化するだけでスタックオーバーフローするって
やっぱC++って腐りきってるよね、C#とかJAVAがいいんだろうな
0146デフォルトの名無しさん2006/11/03(金) 12:26:35
>>145
5^16≒1526億回じゃなかろか?
0147デフォルトの名無しさん2006/11/03(金) 12:31:40
>>135
そうなると C++ 自体が使えないね。
0148デフォルトの名無しさん2006/11/03(金) 13:44:38
どっかで見たことあるいぢめテンプレートだな〜
0149デフォルトの名無しさん2006/11/03(金) 15:36:24
素直に関数型言語使えばいいじゃん。
0150デフォルトの名無しさん2006/11/03(金) 15:47:27
つ elisp
0151デフォルトの名無しさん2006/11/03(金) 17:06:07
>>142
ふつうに再帰関数でもフリーズ。
関数の呼び出し回数が190734863281回にもなるから当たり前だけどな
■ このスレッドは過去ログ倉庫に格納されています