【注意】STLの落とし穴【危険】

このエントリーをはてなブックマークに追加
952デフォルトの名無しさん:2013/09/09(月) 03:19:17.37
constが絡むならstringのコンストラクタ付近で出るだろうし
完全に別のインスタンスになってるこんなところでエラー出るとは思えない
953938:2013/09/12(木) 23:36:07.21
ツールの不具合っぽい方向ですすめることになりました。
いろいろありがとうございました。
954デフォルトの名無しさん:2013/09/14(土) 10:59:23.00
流れ読まずに書くけど、他のオブジェクトへの参照を持つクラスのvectorのpush_bachではまった。

単純化して書くと、

struct person
{
 person* p;
 person(person* other=0) : p(other) { }
 他のメンバ;
};

int main()
{
 std::vector<person> Vec;
 Vec.push_back(person(0));
 Vec.push_back(person(&pV[0]));
 Vec.push_back(person(&pV[1]));
 ・・・

push_backで再アロケートが起こると壊れる。
955デフォルトの名無しさん:2013/09/14(土) 11:03:51.48
>>954
単純化(?)よりも、動いて実際に壊れるコードをだしてくれ。
そうじゃなきゃ、なにが問題かなんてわからんだろ。
956デフォルトの名無しさん:2013/09/14(土) 11:16:44.55
>>955
Vec[n].p == &Vec[n-1]
が成り立ってると思ったら、Vec[n].pが指してる場所は消滅している。

reserveしてからpush_backするか、resizeしてから各Vec[i] へ代入しなきゃダメ。
personはデフォルトのコピコンと代入演算子でOKなクラス。
デストラクタで delete p もしてない。
コンテナの要素としての要件は満たしているんだけどね。
957デフォルトの名無しさん:2013/09/14(土) 11:41:28.85
そりゃおめえvectorの中身のアドレスなんだから
メモリ上の位置変わっても文句言えねえだろ
958デフォルトの名無しさん:2013/09/14(土) 11:41:35.45
なんかおかしくない?
なんでnとn-1が同じところを指すんだか
pVもどこからでて来たかわかんねーし…
959デフォルトの名無しさん:2013/09/14(土) 11:48:43.88
コンストラクタに渡されるのは再配置前のアドレスなんだから当たり前だよなぁ
960デフォルトの名無しさん:2013/09/14(土) 11:55:16.36
>>958
書き間違い
× Vec.push_back(person(&pV[0]));
× Vec.push_back(person(&pV[1]));

○ Vec.push_back(person(&Vec[0]));
○ Vec.push_back(person(&Vec[1]));
961デフォルトの名無しさん:2013/09/14(土) 11:57:34.47
本当に必要だったもの: std::vector<person*>
962デフォルトの名無しさん:2013/09/14(土) 12:07:11.58
コレクション要素を指すポインタを保持したり他に渡したりするのは厳禁、
イテレータも有効範囲に注意してし使わなければならない、ってのはSTLを
使い始めてごく初期に学ぶことと思っていたが。
963デフォルトの名無しさん:2013/09/14(土) 12:47:02.26
>>962
そうだね。外部イテレータが無効になるのは誰もが意識してるだろうけどね。
964デフォルトの名無しさん:2013/09/19(木) 18:34:33.67
今日日、何が悲しくてc++なんて使ってんだろう
965デフォルトの名無しさん:2013/09/21(土) 12:56:57.01
>>961
それ、boost::ptr_vectorにしといた方がいい
966デフォルトの名無しさん:2013/09/22(日) 12:01:45.67
そんな便利な物があったのか
全然知らんかった
967デフォルトの名無しさん:2013/09/22(日) 16:21:09.71
今だったら普通にshared_ptrに包んでvectorに突っ込んだ方が楽だけどな
968デフォルトの名無しさん:2013/09/24(火) 11:11:33.57
ptr_vectorって変な制限が多いでしょ
969デフォルトの名無しさん:2013/09/25(水) 13:08:33.55
>>967
結局そうなるのか
970デフォルトの名無しさん:2013/09/25(水) 15:41:46.87
std::stringのend()って、
必ず末尾のNULL部分なのでしょうか?

>char cLast = *(SBuf.end());
>if (cLast == 0) {
> cLast = *(SBuf.end() -1);
>}

みたいな処理を書いていますが、コンパイラによっては、
1行目で吹っ飛びます(><)
971デフォルトの名無しさん:2013/09/25(水) 15:49:09.49
それ以前に色々間違ってる
972デフォルトの名無しさん:2013/09/25(水) 15:54:58.79
【注意】STLの落とし穴 2 【危険】
http://toro.2ch.net/test/read.cgi/tech/1380091988/
973デフォルトの名無しさん:2013/09/25(水) 15:59:01.05
意外と長寿スレだったぬ
974デフォルトの名無しさん:2013/09/25(水) 17:04:28.72
間違ってるなら、正しい記述を教えて下さいorz
975デフォルトの名無しさん:2013/09/25(水) 17:07:26.77
end()は例えばCで言うと int a[10]; の a[10] みたいなもんで、アドレスとしては有効だけど
領域が確保されてないので中身にアクセスすると未定義

単にイテレータを比較するためのだけのもの
ちなみにイテレータの比較に < を使わず != を使うのは、random_access_iteratorだけじゃないため
976デフォルトの名無しさん:2013/09/25(水) 17:19:58.95
>領域が確保されてないので中身にアクセスすると未定義
有難うございました。

>random_access_iteratorだけじゃないため
今一つ意味が。。。
977デフォルトの名無しさん:2013/09/25(水) 17:53:55.31
>>976
例えばstd::listはbidirectional_iteratorなので要素順としては連続していても
アドレスがあべこべの順になっているなんて事はよくある

だから < で比較しない
というか実際に自分で試してみて「あれっ?」と思う体験が大事
978デフォルトの名無しさん:2013/09/26(木) 04:14:10.98
>>970
std::string で末尾が NULL なのは c_str() でアクセスした場合。
末尾の文字が欲しい場合は
const char cLast = SBuf.empty() ? 0 : *SBuf.rbegin();
とかする。
空文字列の時に rbegin() を逆参照してはいけないので注意。
君の *(SBuf.end() -1) も空文字列の時にダメ。
*(SBuf.end()) は常にダメ。
979デフォルトの名無しさん:2013/09/26(木) 07:49:42.60
'\0' と NULL を混同するんじゃねぇ
980デフォルトの名無しさん:2013/09/26(木) 08:45:35.57
>*(SBuf.end()) は常にダメ。

なるほど、STLの.end()って、ここでしか使ったこと無かったんですが、
既にデータの外だよ、
という意味でしたか。
981デフォルトの名無しさん:2013/09/26(木) 11:16:56.60
イテレータの実装が単なるポインタのvectorでend()の値が何になるか・・・を考えてみればok
982デフォルトの名無しさん:2013/09/26(木) 14:35:55.20
>イテレータの実装が単なるポインタのvectorでend()の値が何になるか・・・を考えてみれば

って、最後の文字のポインタになってて、最後の文字取得出来た方が便利じゃん?
983デフォルトの名無しさん:2013/09/26(木) 15:06:59.12
std::stringとc_str()は違うのよん

int main()
{
std::string str("Test");

std::string::const_iterator pos = str.begin();
for (int i = 0; pos != str.end(); i++, ++pos)
std::cout << "str[" << i << "] = " << *pos << std::endl;

for (int i = 0; i < (int)strlen(str.c_str()) + 1; i++) {
std::cout << std::dec << std::noshowbase << "str.cstr[" << i << "] = '\\";
if (str.c_str()[i] == '\0')
std::cout << "0x00' ←Terminate character" << std::endl;
else
std::cout << std::hex << std::showbase << std::setw(4)
<< std::setfill('0') << (int)str.c_str()[i] << "'" << std::endl;
}
}
984デフォルトの名無しさん:2013/09/26(木) 18:18:29.68
わざわざendやrbeginを持ち出さなくてもbackがあるわけだが
985デフォルトの名無しさん:2013/09/26(木) 20:25:31.13
>>984
そんな事は分かっている
それにrbegin()もあるし
c_str()の場合はどうするんだ?
986デフォルトの名無しさん:2013/09/26(木) 20:52:35.40
>>970を見る限り最後の文字を取得したいだけっぽいからback()で十分なんじゃないの?
>>978とかイテレータを経由する意味がまったくわからないし
987デフォルトの名無しさん:2013/09/26(木) 20:56:02.54
そんなもん人の勝手だろうが
文句あるんなら自分で書け
988デフォルトの名無しさん:2013/09/26(木) 21:35:18.08
中途半端な親切心でレスするのも間違い
989デフォルトの名無しさん:2013/09/26(木) 21:49:00.24
親切心ではなくてこの場合は単なる言い掛かり
ム板なら黙って改良版を書いて示して「こっちの方がすっきりしてるだろ」と言う方がいい
990デフォルトの名無しさん:2013/09/26(木) 22:33:01.27
>>970
char cLast = SBuf.back();
こっちのほうがすっきりしてるだろ
空文字列のときどうしたいのかはわからないから好きにしろ
991970:2013/09/27(金) 09:09:41.20
>char cLast = SBuf.back();

あ、これで最後の文字が取れるんですか。
これが知りたかったことかもwww

>空文字列のとき

は、size()で判定済みなので、無問題です。
992デフォルトの名無しさん:2013/09/27(金) 10:58:13.94
back()はC++11ね
C++03にはない
993デフォルトの名無しさん:2013/09/27(金) 13:57:03.30
>back()はC++11ね

orz
994デフォルトの名無しさん:2013/09/27(金) 16:24:43.00
だから、*(SBuf.rbegin())でいいじゃないの。
995デフォルトの名無しさん:2013/09/27(金) 16:50:23.11
こうしないと空文字列の時未定義の動作

if (SBuf.length())
std::cout << *SBuf.rbegin() << std::endl;
996デフォルトの名無しさん:2013/09/27(金) 17:05:54.46
あ、
>SBuf.rbegin()
てのが最後の文字を指して(rってのは、reverseだとオモ)、
>SBuf.begin()
てのが最初の文字を指すんだ。

orz
997デフォルトの名無しさん:2013/09/27(金) 17:45:49.58
C++03って細かい所で結構未完成なんだな
C++11で結構詰められている
そりゃ8年も掛けたんだもんな
998デフォルトの名無しさん:2013/09/28(土) 01:21:39.38
言語コアの問題、ライブラリの問題が数百件残ってて、今も増え続けている状態。
http://www.open-std.org/jtc1/sc22/wg21/ の Issue List の更新履歴でも見てみるといい。

未完成の割合で言えば、手を広げた分 C++11 のほうがむしろ未完成とも言えてしまう・・・ような気もする。
999デフォルトの名無しさん:2013/09/28(土) 05:49:33.76
もうPL/Iどころの騒ぎじゃなくなって来たな
世界最大規模の言語かよ

もっともライブラリを入れたらJavaやC#もすごい規模なんだけど
1000 ◆Cj98aJOpxg :2013/09/28(土) 06:46:47.54
【注意】STLの落とし穴 2 【危険】
http://toro.2ch.net/test/read.cgi/tech/1380091988/
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。