[obsolete] stringの実装(vc,g++)と扱い方

この記事は陳腐化しました。C++11 から Copy on Write は実装禁止になりました。g++4.5 以降でも消えました。但し、終端文字を必要とする仕様は健在です。

(2013/08/25 追記)

std::stringを参照渡しにすると高速化した。何を言っているのか(ry

なんて記事を見ると改めてstringの扱いはハマるとこ多いよなあと感じる。結論から言うと可能な限りconst&やiterator-pairを使えばいいんですが。

stringは一つの文字列プールを指す文字列クラスで、vectorと次の点で似ています。

  • 連続したアドレス上に保管される
  • メモリは自動で管理される(大抵は一定量から倍々)
  • 要素に’\0’(NULL文字)を使用可能

但し、その実装は処理系によって結構違います。細かいところまでは読んでいませんが、大まかにvcとgccの実装の特徴を紹介します。

g++4.3.4

実装の特徴は、

  • 格納する文字列に必要なプールは常にアロケータから確保
  • プールにCopy on Write(CoW)の実装

stringのコピーの際に文字列プールを共有(参照カウント)して不要な複製をコストを削減しています。以下捕捉です。

  • sizeof(string)がプールへのポインタ一つ分なので引数の受け渡しなどで有利
  • 非constの添字アクセスはほんのちょっと余計な処理が入るかも
  • 空文字列は専用のプールが用意されており領域の確保は起きない
  • 文字列定数は必ずコピーされる
  • 常に終端文字が入っている

実際に変更しなくても、非constで要素にアクセスしたときプール全体のコピーが発生するので、コピーを回避するにはconst必須です。

VC2010

実装の特徴は、

  • 終端文字を含めて16B以下はstringのインスタンス内に入る
  • それ以上はアロケータから確保

16B以下(15文字/wstringなら7文字)の文字列の生成や結合が高速です。短い文字列を大量に扱う場合特に効果を発揮します。以下捕捉です。

  • sizeof(string)は16B+3ポインタ分と大きめ(Debugビルドでは+1ポインタ)
  • 文字列定数は必ずコピーされる
  • 常に終端文字が入っている

主観的な意見

コピーを回避したいならconst&やshared_ptrを使うので、CoWは余計なお節介だと思います。しかもゲームなど応答性が必要な場合、遅延実行の発動タイミングを意識する必要あります。というか長い文字列を扱う場合は別のクラスを使った方が無難です。個人的にはメモリプールの管理と文字列ポリシーを分けてアダプタで繋ぐような実装が欲しいです。

どちらも常に終端文字が入っていますが、本来C形式である必要はなく、それ故data()とc_str()が用意されています。Cと親和性が必要でない限りc_str()は使わなくていいので、特にvcで16文字格納できないのはちょっと勿体無く感じます。またCの関数にdata()を突っ込んでも動くので誤解される原因でもあります。実際は仕様上の制約でデメリットが大きいため終端文字を付けない実装は見たことがありませんが。

ついでに検査用のソースも載せておきます。でも細かい実装は読んだ方が分かり易いです。

#include <iostream>
#include <string>
using namespace std;
int main() {
	string s1, s2 = "a";

	cout << "size of string: "
	     << sizeof(s1) << endl;
	cout << "initial capacity: "
	     << s1.capacity() << endl;

	while ((char*)&s1 <= s1.data() && s1.data() < (char*)(&s1 + 1))
		s1 += s2;
	cout << "capacity inside of string: "
	     << (int)s1.size()-1 << endl;

	s1 = s2;
	cout << "copy on write: "
	     << (s1.data() == s2.data()) << endl;

	return 0;
}

MySQLのテーブルが壊れた

エラー: データベースに接続できません

WordPressのトップにたった一行でかでかと表示されてた。ブレーカーが落ちたせいだな。

WordPress側から復元とかできる仕組みがあるらしいけど、うまく動かなかった。エラーメッセージ的にMySQLの方の問題だろうと思って、コマンドラインで試してみるとデータベースには普通に繋がる。とりあえず片っぱしからアクセスしてみると、

mysql> select * from wp_options;
ERROR 145 (HY000): Table './wordpress/wp_options' is marked as crashed and should be repaired

初めて見たエラーだけどググったら速攻で出てきたので何とかなりそう。それにしてもエラーメッセージがおかしい。「テーブルを読み取れません」とまで分からなくても「データベースに問題があります」程度にしてくれないと原因究明し辛い。

mysql> check table wp_options;
+----------------------+-------+----------+-----------------------------------------------------------------------------------------+
| Table                | Op    | Msg_type | Msg_text                                                                                |
+----------------------+-------+----------+-----------------------------------------------------------------------------------------+
| wordpress.wp_options | check | error    | Table upgrade required. Please do "REPAIR TABLE `wp_options`" or dump/reload to fix it! |
+----------------------+-------+----------+-----------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> repair table wp_options;
+----------------------+--------+----------+------------------------------------------------------+
| Table                | Op     | Msg_type | Msg_text                                             |
+----------------------+--------+----------+------------------------------------------------------+
| wordpress.wp_options | repair | info     | Wrong bytesec:  58- 34- 34 at 296176; Skipped        |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 7572    |
| wordpress.wp_options | repair | info     | Found block with too small length at 194732; Skipped |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 194744  |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 204696  |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 207436  |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 207532  |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 217276  |
| wordpress.wp_options | repair | info     | Key 1 - Found wrong stored record at 244464          |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 246936  |
| wordpress.wp_options | repair | info     | Found block that points outside data file at 297132  |
| wordpress.wp_options | repair | warning  | Number of rows changed from 161 to 150               |
| wordpress.wp_options | repair | status   | OK                                                   |
+----------------------+--------+----------+------------------------------------------------------+
13 rows in set (0.48 sec)

なんとかなった。

もう2011ですか

新年あけましておめでとうございます。今年もよろしくおねがいします。
年賀状は各SNS(non-public)に上げているので知り合いの方は参照してください。

暫く間が開いてしまいました。編入生はやはり忙しい様で、2月中旬まで気を抜けません。下手すると本当に留まります。因みに大学や学部だけじゃなく学科によってまちまちなので、編入を考えている高専生は出来る限り同じ学科(あればコース)の先輩に聞くようにしてください。

年末に友人とサークル(電子工作関係)の製作としてマジキチ仕様のCPUを作ろうとしていました。まだ完成していませんが、ALUの代わりにFPUを作りました。規模はでかいけど組み合わせ論理回路です。加減乗除を実装しています。一応任意精度で使えるように作って単精度,倍精度で動作確認しまた(バグ持ってるかもしれない)。VHDLは大学の演習で触った程度の知識しか無かったので、大半がVHDLやIDEとの格闘でした。丸二日掛かりましたしんどかったです。製作は計画的に。

今週提出の1年の授業の課題でPascalを触る羽目になっているんですが、先行宣言ができず相互再帰関数を定義できないことに失望して課題が放置されています。ダブらないように気をつけます。