vectorとvalarray
vectorとvalarray、どちらを使うべきか迷ったため、調べてみたところ日本語で読める文献が少ない事に驚きました。
ということで、メモメモっと。
02:04 午前 C++ | 固定リンク | コメント (4) | トラックバック (0)
vectorとvalarray、どちらを使うべきか迷ったため、調べてみたところ日本語で読める文献が少ない事に驚きました。
ということで、メモメモっと。
02:04 午前 C++ | 固定リンク | コメント (4) | トラックバック (0)
iostream系は引数が覚えにくいという理由で使ってません。
しかし、気まぐれで使ったstringstreamでちょっとした衝撃を受けました。簡易再現コードは以下の通り。
int i;
double d;
stringstream sstr;
sstr << "10.25"
sstr << "10.50";
sstr >> i;
sstr >> d;
個人的に期待した動作はi=10、d=10.5でしたが・・・
10:07 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
STLは便利ですが、煩雑なエラーメッセージに悩まされる事が多いのも事実です。
そんなときにはSTLFiltをお勧めします。
STLFiltは、STLのエラーメッセージを短くします。対応するコンパイラは10種類以上です。
03:00 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
C++のプロフェッショナルならば、一番外でusing namespaceをすることが、名前空間の汚染にしかならないということは分かっているはずです。
ここはC++言語らしく、使うものは宣言してしまったらどうでしょう?
そこで、using宣言子の出番になります。私が思うに、using namespaceを使うのは手を抜くときだけで十分です。
11:51 午後 C++ | 固定リンク | コメント (2) | トラックバック (0)
浮動小数は近似値である。
大抵の人がそれを理解しているはずですが、以下のコードでcos(a) != cos(b)が成立する可能性がある理由を挙げてください。私が確認した限り、VC++ 6, 2003の/Od(最適化無効)で発生、2005は発生しませんでした。
#include <iostream>
#include <cmath>
int main() {
volatile double a = 1.0;
volatile double b = 1.0;
if(cos(a) != cos(b)) {
std::cout << "cos(a) != cos(b)" << "\n";
}
return 0;
}
12:48 午前 C++ | 固定リンク | コメント (4) | トラックバック (0)
数ヶ月前にふと思い立ってこんな記事を書いたのですが、思ったより反響が大きいため、多少ブラッシュアップしてみました。目的としては「文字列をコピーする作業を含む関数を作成する時に考慮する事」です。
一番簡単な、関数の引数で長さは与えられない状況を検討します。
引き続き、ご指導いただけたら幸いです。
08:10 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
「参照(ポインタ)渡しをすると、アドレスが渡されるので早いんだよ」
それを聞いたAさんは以下のような足し算をする関数を書きました。
int add(const int& a, const int& b);
int add(int a, int b)だった時と比べて、どうなったでしょうか?
1.変わらない 2.早くなる 3.遅くなる
コレを間違えるならば、貴方はC言語の初心者です。
# intをCPUが最も処理しやすいと仮定します
12:20 午前 C++ | 固定リンク | コメント (0) | トラックバック (0)
基礎的な事ですが、ポインタ同士の演算結果はptrdiff_t型です。仮にintと勘違いしても、大きな問題になることは稀ですが、このくらいは覚えておくと良いと思います。
定義はC言語だと<stddef.h>、C++言語だと<cstddef>にあり、符号付きの整数型とだけ定められ、その表現バイト数は処理系定義です。
01:27 午前 C++ | 固定リンク | コメント (0) | トラックバック (0)
最近、Code Completeの第2版を読んでいたわけですが、以下のようなコードも有効らしいです。
さて、最終的なiの出力が幾つになるか分かりますか?
int i = 3, j = 1;
switch(i) {
case 1:
if(j == 0) {
i += 2;
break;
case 3:
i++;
}
break;
}
printf("i = %d\n", i);
11:49 午後 C++ | 固定リンク | コメント (4) | トラックバック (0)
C++でクラスの配列を作る方法は以下の3つの方法をとるのが普通です。
12:52 午前 C++ | 固定リンク | コメント (0) | トラックバック (0)
C++の名前空間は別名を付ける事が出来ます。
例えば以下のように複雑な階層構造をもつクラスがあるとします。
namespace Win32
{
namespace Network
{
namespace Http
{
class Connection
{ };
}
}
}
Win32::Network::Http内のConnectionクラスを使うのに長々とタイプしたくない場合は以下のように定義します。
10:29 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
クラスのメンバ変数は初期化順序が規約により決まっています。
例えば以下のクラスのメンバ変数はどの順番で初期化されるでしょうか?
class T
{
int a;
int b;
int c;
T() : c(5), a(2), b(4) { };
};
09:14 午後 C++ | 固定リンク | コメント (2) | トラックバック (0)
標準C++では、負の数に対する除算の結果が保証されません。
手元にある標準C++(X3014:2003)の仕様書にある剰余演算子の項目には以下のように書かれています。
09:23 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
関数呼び出しを理解する最後のポイントはextern "C"です。
externは通常はリンケージ宣言子ですが、C++の仕様では、"C"などのリテラルがついた場合、他の言語の宣言を変換して利用できるようにする、と書かれています(つまり、リンケージ変換宣言子?)。
結果としてC++からCで作られた関数を呼ぶにはexternが必要になります。また、CからC++で作られた関数は呼べないのです。
01:11 午前 C++ | 固定リンク | コメント (0) | トラックバック (0)
今回は、呼び出し規約について説明していきます。
呼び出し規約は関数の引数の引き渡し方、引数利用後の処理の仕方を制御します。
これが関数の装飾名にも影響を与えます。
03:14 午後 C++ | 固定リンク | コメント (2) | トラックバック (0)
内部を知らない人はWindowsのDLLで関数が正しく呼べないことが多いです。
また、UNIXを使う方も知識として覚えておいて損はないです。
C++の関数呼び出しについては、コンパイラとリンカが関係しています。
11:51 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
実装例をよく見ますが、仕様からするとNoです。
そんなの当たり前でしょ、という方はこれ以上読む必要はありません。時と場合によるだろ、と思ってる方は一応読んでみてください。
02:00 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
当然ですが、Noです。安全に使うことが非常に難しいだけです。
strcpyの定義は
char *strcpy(char *dst, const char *src);
ですが、以下の条件が全て成立しなくてはならない事に問題があるのです。
11:49 午後 C++ | 固定リンク | コメント (6) | トラックバック (0)
標準C++の規約によると不可能です。諦めてください。
C++では例外が起こると、catchを見つけるまで「スタックの巻き戻し」が行われる事が決まっています。
11:12 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
良く、Visual C++は標準じゃないからとか、GCCは標準に準拠しているとか聞きます。標準とはいったい何なのかという話です。
C言語とC++は別の課程で標準化が行なわれております。そのため、分けて説明するのが適切です。また、標準化団体にも色々ありますが、国際標準であるISOを基準にして考えるのが普通でしょう。
11:49 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
理由もなくvirtualにしていませんか?
ご存知のとおり、virtualと宣言すると、クラスの初期化や破棄にかかる処理が増えます。必要がない場合は使用を避けるべきなのです。
01:00 午前 C++ | 固定リンク | コメント (2) | トラックバック (0)
Microsoftの「Visual C++ 2005 Express Edition」が1年間限定で無料配布中です。
もちろん制約があるわけですが、私が厳しいと思う制約は以下の通り。
11:35 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
C言語においてビットシフト演算子(<<や>>)は2通りに解釈される。
どちらが適用されるかは、型が符号を持つかに依存する。
signedである場合は算術シフト、unsignedの場合は論理シフトである。しかし、符号付整数の右シフトだけは結果が処理系に依存(※1)してしまう。浮動小数型の場合、シフト演算自体が無効である。
signedである場合は算術シフト、unsignedの場合は論理シフトになり、符号ビットを持つfloatやdoubleは算術シフトになる。結局は何の違和感もないように出来ているだけだ。
---
※1 Cでは、整数の内部表現を2の補数に決めていないため、下手に規定しないほうが高速なように実装を選べる余地が残せるという事なのだろうか?もっと詳しく知りたいため参考情報募集してます。
---
[MSDN] - C++ Language Reference Shift Operators: >> and <<
---
にて詳しい解説を作られたようです。こちらも是非参考に。
---
(2006/01/05) コメントによる指摘により訂正。progerさん有難うございました。
(2006/01/09) 不適切な表現を修正。参考となるリンクを追加しました。
01:35 午前 C++ | 固定リンク | コメント (8) | トラックバック (1)
operator newで生成したクラスはコンストラクタを呼ばない。
他の用途としてはクラスの配列(※1)を動的に使いたい時に便利。
T* pClsArray = new T[size]; // デフォルトコンストラクタで初期化
初期化されては困る場合に以下のようにする。
T* pClsArray = static_cast<T*>(operator new [](sizeof(T) * size)); // メモリ確保のみ
・・・
new (&pClsArray[n]) T(); // 配置newで必要な時に作成
デフォルトコンストラクタ以外もちゃんと指定できる。
メモリの解放はoperator deleteを使う。
operator delete [] (pClsArray); // メモリの解放
配置newにdeleteは要らないが、メモリの解放前にデストラクタを手動で呼び出す。
pClsArray[n]::~T(); // これが忘れがち
もちろん配列の個数分必要。
※1 vectorを使う方法も有ります。
---
(05/12/05) 加筆&文法ミスを修正。
12:33 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
が未だに悩みます。
クラスがポインタ型の変数を持つ場合です。
この際はデフォルトのコピーコンストラクタが使い物にならなので自分で書かなくてはなりません。中身の全てをヒープ(フリーストア)にとっておくのが唯一の正解と思っています。参照カウンタを使っても呼び出し元の不正を完全に防ぐのは難しいし。それでも悩むのはコピーのコストを気にしすぎなんでしょう。
結局は、「呼び出し元が賢いと仮定する」か、「解放の責任を負わせない(≒余計なメモリを消費して安全)」かの2択になります(auto_ptrやshared_ptr(※1)は呼び出し元が賢いと扱う)。
答えの違い(※2)を楽しめるのが「C++(※3)」って事で。
※1 C++のデファクトスタンダート?なライブラリ「boost C++」内にある参照カウンタ付きのポインタ。これが常に使えれば個人的には解決なのですが・・・。
※2 毎回違うのが正解という考え方もあります。オブジェクトが小さければコピーを取っても良いし、大きければコピーを生成するのは悪です(一瞬とはいえ、2倍以上メモリを使用します)。最近はプロトでさえ常に安全サイドに傾かせています。
※3 「Managed C++」や「Java」はメモリ管理で楽しめないため嫌いです。
03:03 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
最近、定数の後にLをつけろいったら何ソレといわれました。
C++の規約では整数はint、少数はdoubleになります。末尾に特別なアルファベットをつけるとそれを変更することが出来ます。
符号無し 0U
LONG型 0L
FLOAT型 1.0F
他もあると思いますが、一般的にはこのくらいかと。
---
(05/12/08) doubleについて抜けていたのを追記。
04:34 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
「キャストをしてみたらコンパイルが通った」などという話を聞きます。
私の前でこんな事を言うと、駄目プログラマのレッテルがアロンアルファでくっつきます。キャストに関わるTipsを少し。
■ 絶対にC++形式のキャストを使う
具体的にはstatic_cast, dynamic_cast, const_cast, reinterpret_castです。C++形式のキャストはC形式のキャストに比べて非常に安全です。当然、人のソースと接続するために、どうしてもキャストしなければならない場合だけ利用します。
詳しくはMSDNの記事、「Deep C++」の「static_cast」あたりから読むと良いと思います。
私のオススメはconst_castです。コイツはconstを付けたり消したりする事しか出来ない。Cのキャストに慣れた方は、制約されたキャストを使用する事から始めましょう。
■ C++のoperatorを理解する
C++の組込型(int, double等)以外、型が勝手に変換される(※1)なんて事はありません。例えばStringというクラスに対して「operator const char*() { return 中身; }」などと定義する事によって、利用者が意識せずともStringがchar*型に変換されているだけです。つまり、意識しないとoperatorは凄く危険(※2)です。
CStringなどをなんとなく利用して、なんとなく変換してもらってるという状況はやめましょう。型が変わっている時は再確認(※3)する。基本です。
とりあえずこの2点ですね。気づいたらまた書くかもしれません。
C++の設計者は、「C++のキャストは置換しやすく、「敢えて」打ちにくくした。本来キャストなど不要だ。」という趣旨の話をしております。
※1 暗黙の型変換はコンストラクタのみに存在します。int型なのにdouble型として初期化したりしますが、当然i余計にスタックを確保している事をお忘れ無く。一時オブジェクトと呼ばれちょっとした嫌われ者です。(興味ある人は暗黙の型変換を禁止する「explicit」も調べてみてください)
(05/11/10追記)
operatorを暗黙の型変換と呼ぶ人もいます。私は、(警告は出るが)型が違ってもコンパイルを成立させてしまうものを暗黙の型変換と呼ぶことにしてます。
※2 C++の標準ライブラリであるbasic_stringがchar*に対するoperatorを使わずに「c_str」なんて関数を定義したか、良く考えましょう。分からないうちは自分で定義してはいけません。
※3 組込型以外は必ずincludeしているヘッダにtypedef式があります。型がoperator式を持つクラスな場合、ヘッダには宣言部分が存在します。
03:57 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
最近出た本である「C++ Coding Standards」を買いました。
著者は「C++ Depthシリーズ」の過去の著者二人です。素晴らしく良くできているとおもいますので是非読んでみてください。
constについての見解も再掲載されていました。
■値渡しの場合、関数宣言(※1)にconstは不要
同氏が前書いたことと若干違います。
違う点は
int Func(int nVal);
と宣言し、実際は
int Func(const int nVal)
{ ・・・ }
と定義する例を追加した点。
コレ、実は私もやっていました。確かに変数を弄る危険はなくなりますが・・・。
定義の一部にconstを書き忘れて、統一性が無くなる。(経験則)
コンパイラがこの2つを同等に解釈する(事が多い?)のを知らない人も居る為、混乱を招く。(特にクラスのメンバ関数)
そうなる位なら宣言にもconstを付けて定義はコピペした方が良いと思うんですが。Grepも置換もしやすいですし。
※1 宣言と定義の区別がついていない人、結構います。ヘッダファイルに書くべき事が宣言、ソースファイルに書くべきなのが定義です。不安だったら調べなおしましょう。(最近はヘッダに実装を書かざるを得ない場合もあります。VC++もexportのサポートを切望。)
08:37 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)
関数の仮引数編。元ネタはExceptional C++。
■値渡しには不要。
■ポインタ渡し、参照渡しには必要。
void Func(int nVal);【値渡し】
void Func(const char *szStr);【ポインタ渡し】
void Func(const T& cls);【参照渡し】
特に異議無い。しかし、私の中では例外あり。
■Win32プログラミングでバイト列を読み込む
void Func (const BYTE* pbDoc, const DWORD cbDoc);
constを対照にする為だけに利用。
Win32APIでは「const BYTE*」を「LPBYTE」に「typedef」して利用、自然に見える。
だが、この手の関数は、BYTE*で受けて参照することも多い。関数内でconst BYTE*による参照を強制したいし。
ちなみに、文字列には「LPCSTR」が存在するので問題なし。
11:44 午後 C++ | 固定リンク | コメント (0) | トラックバック (0)