( 「densuke」さんという方の真似です。ehehe... )
その昔,「インターネット」はリソース同士のリンクによる素晴らしい「くもの巣」が構成されていました
当時の私たちは,全てのリソース位置情報を自由自在に扱うことにが許されました。あたかも生物の脳のように複雑にからみ合ったそれは,私たちに無限の可能性を与えることを微塵も惜しむことはなかったのです。
──そして 2002 年夏。
それら全てを「過去のもの」とし,全力で否定するサイトが登場しやがりました。「クッキー」「データベース」などの最新技術を総動員し,土足の訪問者を思う存分排除し始めたのです。
「リンク不可,検索サイト UZEEEE」「訪問はトップページからのみ」「クッキーが使えなければアクセス拒否」「質問は管理者へ。ただし管理者のメールアドレスが分かれば,ね(笑)」・・・こんなのが,これから「当たり前」になってゆくのでしょうか。全ては時の流れのままに。人の世は移り変わるもの。仕方がない事なのかも知れませんね・・・。
・・・ていうか,こんなの WEB じゃないし!?
早とちりした自分への戒め:文化庁は「これは多分マズいんだろうなあ」という姿勢の模様。願わくは,こんな事で私たち国民の利益を損ないませんように。
なんだか脱力しっぱなしなんで・・・。
七夕といえば織姫と彦星。しかし最近は全然星が見えないので,なんだかよくわからなくなってます。
んで昨日の雑記,日付を変えるのを忘れて「2002-07-06」などとヤってました。最近暑いから・・・。
今回のネタも数回に分けるべきだと思いました。長くなるんで。
もうそろそろ時期も適当かなということで,最近私が体験したウィルス騒動のネタです。といってもウィルスをもらったのは私じゃなくて,全く知らない人なんだけど。
何の因果かは分かりませんが,まれに「ウィルスに感染したっぽいんだけど,どうしたらよいでしょうか?」という質問が寄せられます。無下に「知るかっ」と返信するのもアレなんで,勉強がてらにアドバイスをしてあげたりしています。・・気が向いた時だけ。
最近の事例はこんなの:( 改変してあります )
( ブラウザを起動させると ) 勝手に猥褻なサイトにアクセスしてしまう。どうすればよいだろうか?
最初に来たメールはこんな感じの意味にとることができました。実際には──さすがに私のようなぁゃιぃ人間に質問をするだけあって──もうちょっと・・その・・可愛げのある文章だったのですが。いい意味で。
大抵この場合,レジストリに問題があります。次のように「ファイル名を指定して実行」を選び・・・
「regedit」と入力すると,レジストリエディタが起動されます。
ツリーを HKEY_LOCAL_MACHINE - SOFTWARE - Microsoft - Internet Explorer - Main と辿ると, Default_Page_URL や Default_Search_URL という項目が見つかります。
PNG ファイル (15.5KBytes) / PNG ファイル (27KBytes)
ここが怪しい URL になっているはずなので,好きな値に変えてしまいましょう。
PNG ファイル (18KBytes) / PNG ファイル (3.4KBytes)
のような感じでアドバイスをしてみたのですが・・・これでは解決しなかったのだから大変。続きますよ。
試行錯誤度:4992
レジストリをいじらなくても,IE の設定でどうにかなるという罠。物事を難しく考えるのは私の悪いクセなんですよねー。とほほ。
おとといと昨日で構造体のかなりディープなトコロを扱ってきました。さて,今日は構造体の中身を全部きれいに表示させてみたいと思います。これが意外に面倒だったですよ。。。
sub deep_print {
my $indent = 0;
my $do_indent = 1;
sub deep_print_sub {
my $ref = shift;
my $old_indent;
if (ref $ref eq 'HASH') {
print ' ' x $indent if $do_indent;
print "{\n";
++$indent;
scalar keys %$ref;
while (my ($k, $v) = each %$ref) {
print ' ' x $indent;
print "'$k' => ";
$do_indent = 0;
&deep_print_sub($v);
$do_indent = 1;
print "\n";
}
--$indent;
print ' ' x $indent if $do_indent;
print "},\n";
}
elsif (ref $ref eq 'ARRAY') {
print ' ' x $indent if $do_indent;
print "[\n";
$do_indent = 1;
++$indent;
for (@$ref) {
&deep_print_sub($_);
print "\n";
}
--$indent;
print ' ' x $indent;
print "],\n";
}
else {
print ' ' x $indent if $do_indent;
if ($ref - 0 eq $ref) {
print "$ref,";
}else{
print "'$ref',";
}
}
}
&deep_print_sub(shift);
}
コード長いしー。しかも関数が入れ子になってるしー。
この関数で,おとといから使っているあの複雑な構造体をキレイに表示させることが出来ます。こんな感じで:
&deep_print($structure);
実行結果はこう:
{
'hobbies' => [
'WRITING PROGRAMS',
'MUSIC',
'HEHEHE...',
],
'machines' => [
{
'memory' => 32,
'hard drive' => 3.2,
'CPU' => 200,
'name' => 'FMV-TOWNS',
},
{
'memory' => 64,
'hard drive' => 10,
'CPU' => 500,
'name' => 'VAIO',
},
{
'memory' => 128,
'hard drive' => 40,
'CPU' => 1400,
'name' => '(main machine)',
},
],
'age' => 23,
'name' => 'kuri|minima',
},
おおっ,本当にこれほどキレイに表示されるとは思いませんでした ( 自画自賛 )。最後尾の <,> 文字を <;> 文字に置き換えると,このままリファレンスとして他の変数に代入することも可能です。
疲労度:534
ついに買ってしまいましたよ,「プログラミング言語 C++」。試行錯誤,ネット検索,C Magazine での勉強に限界を感じて早・・はや・・はや・・・・ 7 ヶ月!!!??
そう,某掲示板で「そろそろまともな本が欲しいっす・・」とつぶやいたのが昨年 11 月。それから 7 ヶ月も試行錯誤 etc を続けていました。アホか,自分っ!
それはともかく,ウィンストン・チャーチルの言葉「私が割り込んでいる間に 私に割り込むな」は名言だと思いました。どこでも応用が利きますね。
・私が印刷をしている間に,私を印刷をするな
・私が検索をしている間に,私を検索するな
・私が挿入している間に,私に挿入するな
ん,いい感じです。
昨日の予告通り,今日は複雑な構造体の「ディープコピー」を行ってみます。ここで「ディープコピー」とは:
my $src = {
...(ぐちゃぐちゃな構造)
};
my $dst = &deep_copy($src);
として,$dst をどんなにいじっても $src に影響を与えないような,完全なクローンを作ることを指すことにします。具体的なコードはこう:
sub deep_copy {
my $ref = shift; # 構造体のリファレンスを入力
if (ref $ref eq 'HASH') {
my %hash = ();
scalar keys %$ref; # イテレータをリセット
while (my($k, $v) = each %$ref) {
$hash{$k} = &deep_copy($v);
}
return \%hash;
}elsif (ref $ref eq 'ARRAY') {
my @array = ();
push @array, &deep_copy($_) for (@$ref);
return \@array;
}
$ref;
}
昨日のネタ「値を 10 倍にする関数」によく似ています。要するに Perl サブルーチンの再帰の面白い応用例の 1 つってわけですね。
明日は構造体の中身を全て print してみます。
Perl に「構造体」なんかあったかなぁ? などと言っちゃいけません。「連想配列」,これこそは誰がどう見ても明らかに C の構造体ですが文句あるか。
Perl の構造体で楽しいのは,グッチャグチャな構造も比較的簡単に書けるということ。あくまでも書くのが簡単なだけで,実際に扱うと確実に脳みそがどうにかなりますんでご注意。
my $structure = {
'name' => 'kuri|minima',
'age' => 23,
'hobbies' => ['WRITING PROGRAMS', 'MUSIC', 'HEHEHE...'],
'machines' => [
{
'name' => 'FMV-TOWNS',
'CPU' => 200,
'memory' => 32,
'hard drive' => 3.2
},
{
'name' => 'VAIO',
'CPU' => 500,
'memory' => 64,
'hard drive' => 10
},
{
'name' => '(main machine)',
'CPU' => 1400,
'memory' => 128,
'hard drive' => 40
}
]
};
書いている自分もワケが分からなくなりましたが,とりあえずこれで
print $structure->{'machines'}[2]{'memory'};
128 と出力されるはずです。私が今使っているパソコンのメモリのサイズです。
ここで問題。構造体内にある数値を全て 10 倍にしたくなりました。どうすればよいでしょうか?
こんな感じでは・・・
# オススメできない例
$structure->{'age'} *= 10;
$structure->{'machines'}[0]{'CPU'} *= 10;
$structure->{'machines'}[0]{'memory'} *= 10;
以下略
データを増やしたりメンバを増やしたり,構造を今より複雑にするとお花畑が見えます♪ 本当にシャレにならないので,構造体を全て走査することができる,こんな関数を作ってみました。
# 数字のデータを 10 倍する
sub x10_foreach {
my $ref = shift; # リファレンスを入力
if (ref $ref eq 'HASH') {
scalar keys %$ref; # イテレータをリセット
while (my($k, $v) = each %$ref) {
$ref->{$k} = &x10_foreach($v);
}
return $ref;
}elsif (ref $ref eq 'ARRAY'){
$_ = &x10_foreach($_) for (@$ref);
return $ref;
}
# 数字と文字列を区別する・・んだけど・・
if ($ref - 0 eq $ref) {
return $ref * 10;
}
$ref;
}
$structure = &x10_foreach($structure);
print $structure->{'machines'}[2]{'memory'};
確かに 1280 と表示されます。お試しあれ。
なお,これには '10' という文字列が 100 になってしまうという問題も残っています。Perl が文字列と数値を区別しないからですね。一応,簡単に区別できるトリックを仕込んではありますが,この問題だけはどうしようもないようです。回避手段としては,文字列であることを表すために ' 10' などと余分な空白を追加しておくとか・・・。
珍しく明日の予告:構造体のディープコピーについてのコードも書いてみます。今日のコードと殆ど変わらないですけどね。
きっと世界中の誰もその言語仕様を完全には理解していないはずだと噂されている C++ ですが,私は徐々にラベルを上げつつありますよ。
基底クラス A と,そこから派生したクラス B を考えます。こんな感じ。
#include <stdio.h>
class A{};
class B : public A {
const char *str;
public:
B(): str("[ no args constructor ] made me.") {
printf("no args constructor 0x%x\n", this);
}
B(const A &a): str("[ A copying constructor ] made me.") {
printf("A copying constructor 0x%x\n", this);
}
B(const B &b): str("[ B copying constructor ] made me.") {
printf("B copying constructor 0x%x\n", this);
}
~B() {
printf("B destructor 0x%x\n", this);
}
const char *method() const { return str; }
};
B func() {
B b;
return b;
}
int main() {
puts( func().method() );
return 0;
}
no args constructor 0x64fdc4 B copying constructor 0x64fde8 B destructor 0x64fdc4 [ B copying constructor ] made me. B destructor 0x64fde8
クラス B はインスタンス生成時に,どのコンストラクタが呼ばれたかを出力しています。またインスタンス自身も,自分がどのコンストラクタで生成されたかを憶えておきます。
この例では func() 関数内でインスタンス b が引数なしのコンストラクタで生成されます。そして関数を抜ける時にクラス B をとるコンストラクタ「コピーコンストラクタ」で仮のオブジェクトを生成しています。method() を無事に呼び出して puts() が終わると,仮のオブジェクトも破棄されました。
ここでちょっとしたイタズラ心。コピーコンストラクタとして B(const A &a); が呼ばれないかなあ? ということで実験してみました。方法は簡単。単純にコピーコンストラクタ B(const B &b) をコメントアウトするだけです。
// コメントアウト
//B(const B &b): str("[ B copying constructor ] made me.")
//{
// printf("B copying constructor 0x%x\n", this);
//}
no args constructor 0x64fdc4 B destructor 0x64fdc4 [ no args constructor ] made me. B destructor 0x64fde8
やはり B(const A &a) はコピーコンストラクタには成り得ないようです。しかし実行結果にそこはかとない違和感が。えーっと,状況を冷静に分析しなければなりません。
っ!?
そこで瞬時に閃きました。「きっとデフォルトのコピーコンストラクタが働いているに違いない」とね。
デフォルトのコンストラクタ内には puts() などというコードが存在しないため,表立ってそれが呼ばれたとは気付きません。そのくせメンバ変数 str がちゃんとした文字列を保持していたのは,前のオブジェクトのそれがそのままコピーされたものです。
さて,ここで私の調査は終了。本当にその「デフォルトのコピーコンストラクタ」が呼ばれているのかどうかを探るべきなのかも知れませんが,残念ながら ( 少なくとも私には ) デフォルトのコピーコンストラクタのコードを覗くことはできません。
今回の例で重要なことは,コピーコンストラクタで特殊な処理をさせたいならば,必ず明示的に定義しておかなければならないということ。それから,基底クラスを引数に取るコンストラクタは,コピーコンストラクタの代わりにはならないということ。
参照カウンタで内部のメモリを管理しているようなクラスでは,このミスで不思議な挙動を起こしてくれました。経験者語る,です。
疲労度:90
同サイトの TechTips は前々からお世話になっていました。実際に仕事で使わせて頂いたりもしたんですよ。・・えーっと,Visual C の項目しか見ていないんですけどね。
んでこの「ディスカッション フォーラム」では,Tips では解決できなかった細かい疑問を持ち寄ってみんなで解決しています。・・んーと,Visual C の項目しか見ていないんですが。
別にいいじゃんっ! 2ch は多くの人が集まったため,玉石混交の情報の中から "玉" のみを抜き出すコストが無視できません。その点,このフォーラムはまったりしてます。日々の作業でなんとなーく "息が詰まった" ような時にちょっと覗いて,初心者の振りをして質問をするもよし,逆に初心者さんの質問に答えるもよし。・・・て,別にネタ掲示板じゃないんですけどね。
なんか無茶苦茶失礼な紹介になったけど,実際,用意された場所のゴージャスさの割には大盛況ってわけでもないんですよね。しかし,ネット上のリソースの質を向上させるには,充分な役割を持っていたりします。
疲労度:44
うーん,ちょっと疑問です。・・・それだけ。
Mozilla のコーディングスタイルのガイドとかを読んでいると,"nsAutoString を使え" という記述に出くわします。何度も出入りを繰り返すような関数内で文字列を使う場合,何度も malloc と free でヒープをいじり続けることで徐々に断片化を起こし,アプリケーションの効率が悪くなるらしいです。しかしあらかじめヒープを取得しておき,明示的にその場所を何度も使いまわすことが出来るなら,メモリも効率よく扱うことが出来るでしょう。それをクラス化したのが nsAutoString だとか。
そこで私もちょこっと考えました。例えばあらかじめ char str[64]; ってスタックに積んじゃえば malloc 関数を ( 少なくとも私たちは明示的には ) 使うことがありません。メモリが足りなければ,そもそもアプリケーションが起動しませんしね。
これをクラス化するとかっちょいいかも? ということで組んだのがこんなコード。
->SolidSequence クラスとデモ "ss.cpp";
SolidSequence を素直に使うなら,普通はこんな感じ。
int main() {
SolidSequence<char, 64> str = "hello, solid string!";
puts (str.get());
return 0;
}
しかし「自分は文字列と言えば char 配列しか使わないんだ!」というポリシーを持つなら,なんとなくこんな事をしたくなります。
// 注意:これはできません
template<int MaxLen> typedef SolidSequence<char, MaxLen> SolidString;
SolidString<64> str = "hello, solid string!";
char の部分は固定させたいんですが,なぜか C++ はこれをサポートしていません。そこで考え出されたのがこんな芸当。
template<int MaxLen>
struct Solid {
typedef SolidSequence<char, MaxLen> String;
};
int main() {
Solid<64>::String str = "hello, solid string!";
return 0;
}
これが Rebind と呼ばれている技です。滅多な場所では使わないかもしれませんが,憶えておくと意外な場所で便利だったりして。
疲労度:38