プログラミング、ゲームシステムなど普段考えたことについてのメモ帳代わり。
No.9
2010/01/29 (Fri) 07:32:12
卒論のプログラム作成中、エラーが起き、「vector iterators incompatible」というメッセージが表示された。
STLのvectorを利用した際に起こるもので、要素の削除に関連したもの。
前にも何度かやっていて、よく分からずにその当時は投げていた。時間に余裕があるわけではないが、今回はその理由を探ってみた。
プログラムは下記のようなものだ。かなり単純化してはあるが、構造は同じである。
----------------------------------------------------------------
vector v;
v.push_back(10);
v.push_back(-2);
v.push_back(3);
v.push_back(-10);
for(vector::iterator it = v.begin(); it != v.end(); it++){
if(*it < 0){
v.erase(it--);
}
//この後、エラーが起こる
}
----------------------------------------------------------------
「イテレータが不正」とのことなので、とりあえずブレークポイントをしかけてみるものの、「it」には特に問題がない。
そこで試しに、「begin()」と「end()」を取得してみた。
----------------------------------------------------------------
if(*it < 0){
v.erase(it--);
vector::iterator b_it = v.begin();//vの最初の要素を表すはず
vector::iterator e_it = v.end();//vの最後の次の要素を表すはず
}
----------------------------------------------------------------
すると、「b_it」は予想通り最初の要素を表したが、「e_it」は最後の要素を表していた。
本来は最後の次の要素を表さなければならないので、ここで「end()」が狂っていることがわかる。
なぜそうなるのか、詳細は分からないが、結局イテレータでループを回しつつ「erase()」することで問題が出ることは分かった。
ので、ループカウンタを使っての配列アクセスにしつつ削除の際はイテレータを取得して「erase()」するようにした。
結果、エラーは起こらなくなった。詳細については後日調べようと思う。
----------------------------------------------------
for(unsigned int i = 0; i < v.size(); ){
if(v[i] < 0){
vector::iterator it = v.begin() + i;
v.erase(it);
}else{
//erase()は後ろの要素を詰めるので、erase()しなときのみカウンタを回す
i++;
}
}
----------------------------------------------------
上記は修正結果である。
あまり良いプログラムには見えない。
STLのvectorを利用した際に起こるもので、要素の削除に関連したもの。
前にも何度かやっていて、よく分からずにその当時は投げていた。時間に余裕があるわけではないが、今回はその理由を探ってみた。
プログラムは下記のようなものだ。かなり単純化してはあるが、構造は同じである。
----------------------------------------------------------------
vector
v.push_back(10);
v.push_back(-2);
v.push_back(3);
v.push_back(-10);
for(vector
if(*it < 0){
v.erase(it--);
}
//この後、エラーが起こる
}
----------------------------------------------------------------
「イテレータが不正」とのことなので、とりあえずブレークポイントをしかけてみるものの、「it」には特に問題がない。
そこで試しに、「begin()」と「end()」を取得してみた。
----------------------------------------------------------------
if(*it < 0){
v.erase(it--);
vector
vector
}
----------------------------------------------------------------
すると、「b_it」は予想通り最初の要素を表したが、「e_it」は最後の要素を表していた。
本来は最後の次の要素を表さなければならないので、ここで「end()」が狂っていることがわかる。
なぜそうなるのか、詳細は分からないが、結局イテレータでループを回しつつ「erase()」することで問題が出ることは分かった。
ので、ループカウンタを使っての配列アクセスにしつつ削除の際はイテレータを取得して「erase()」するようにした。
結果、エラーは起こらなくなった。詳細については後日調べようと思う。
----------------------------------------------------
for(unsigned int i = 0; i < v.size(); ){
if(v[i] < 0){
vector
v.erase(it);
}else{
//erase()は後ろの要素を詰めるので、erase()しなときのみカウンタを回す
i++;
}
}
----------------------------------------------------
上記は修正結果である。
あまり良いプログラムには見えない。
PR
No.7
2009/08/16 (Sun) 19:50:11
今更だけど、メンバ関数コールバックは、
&クラス名::メンバ関数名
ってやらないとアドレス受け取れないらしいね。
……3月に書いたことにツッコんでもなぁ。
&クラス名::メンバ関数名
ってやらないとアドレス受け取れないらしいね。
……3月に書いたことにツッコんでもなぁ。
No.3
2009/03/23 (Mon) 16:22:45
さほど調べずに書いています。
私は大抵やっつけ仕事なのでC++の仕様などあまり知らないのですが、
--------------------------------------
class Charactor{
private:
void Attack();
void Dush();
void Stand();
public:
void (*Action)();
void Init();
public:
Charactor();
virtual ~Charactor();
};
Charactor::Init(){
Action = &Stand;
}
大体、virtualつけてもいないのに仮想関数って・・・つまりメンバ関数は仮想関数と同義(そのクラス内に限った――継承関係を考えない場合)ってこと?
詳細は後で調べるとして・・・ 同様の方法を取るならstaticしかなく、staticにするとメンバ変数がダイレクトに扱えないから結局ダメ。
そうすると、やっぱり
--------------------------------------
enum ENUM_CHARACTOR_ACTION{
ACTION_STAND,
ACTION_ATTACK,
ACTION_DUSH
};
class Charactor{
private:
ENUM_CHARACTOR_ACTION m_enum_action;
private:
void Attack();
void Dush();
void Stand();
public:
void Action();
void Init();
public:
Charactor();
virtual ~Charactor();
};
Charactor::Init(){
m_enum_action = ACTION_STAND;
}
Charactor::Action(){
switch(m_enum_action){
case ACTION_STAND: Stand(); break;
case ACTION_ATTACK: Attack(); break;
case ACTION_DUSH: Dush(); break;
default: break;
}
}
--------------------------------------
みたいな感じになるのかね。
色々と誰かに聞きたい気はするけれど、あくまでこのページはメモ帳。コメントを残せるようにしたり新着がトップに上がるようにしたり・・・ということはしない方向で。
・メンバ関数はインスタンス化されない限り仮想関数扱い
・↑の文に騙されてはいけない
・詳細は改めて調査すべし
と、いうことでした。
私は大抵やっつけ仕事なのでC++の仕様などあまり知らないのですが、
--------------------------------------
class Charactor{
private:
void Attack();
void Dush();
void Stand();
public:
void (*Action)();
void Init();
public:
Charactor();
virtual ~Charactor();
};
Charactor::Init(){
Action = &Stand;
}
--------------------------------------
大体、virtualつけてもいないのに仮想関数って・・・つまりメンバ関数は仮想関数と同義(そのクラス内に限った――継承関係を考えない場合)ってこと?
詳細は後で調べるとして・・・ 同様の方法を取るならstaticしかなく、staticにするとメンバ変数がダイレクトに扱えないから結局ダメ。
そうすると、やっぱり
--------------------------------------
enum ENUM_CHARACTOR_ACTION{
ACTION_STAND,
ACTION_ATTACK,
ACTION_DUSH
};
class Charactor{
private:
ENUM_CHARACTOR_ACTION m_enum_action;
private:
void Attack();
void Dush();
void Stand();
public:
void Action();
void Init();
public:
Charactor();
virtual ~Charactor();
};
Charactor::Init(){
m_enum_action = ACTION_STAND;
}
Charactor::Action(){
switch(m_enum_action){
case ACTION_STAND: Stand(); break;
case ACTION_ATTACK: Attack(); break;
case ACTION_DUSH: Dush(); break;
default: break;
}
}
--------------------------------------
みたいな感じになるのかね。
色々と誰かに聞きたい気はするけれど、あくまでこのページはメモ帳。コメントを残せるようにしたり新着がトップに上がるようにしたり・・・ということはしない方向で。
■■■まとめ
・メンバ関数はインスタンス化されない限り仮想関数扱い
・↑の文に騙されてはいけない
・詳細は改めて調査すべし
と、いうことでした。
| HOME |