amazon検索
最近のコメント
Recent Entries
Archives
Search


Links
Calendar
2023年10月
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Powered by
Movable Type 2.65
カテゴリ別アーカイブ
N88Basic [4件]
RadioSharkPlayer [14件]
VBA [2件]
VC [4件]
VSTi_ChordMaster [8件]
アセンブラ [2件]
知識 [5件]
TOTAL:

TODAY:

YESTERDAY:


2023年09月13日

_新版明解C++中級編/著:柴田望洋 正誤表


自分が気づいたところをアップ!優しさのカタマリ。初版の2004年3月31日を手元にして執筆したものです。

P248-P249
Shape3/Line.h
49行目
×std::cout << '-'
〇std::cout << '*'

75行目
×std::cout << "|\n"
〇std::cout << "*\n"

あるいはプログラム動作結果の方を合わせるかしないといけません。

P266
chap07/IOBuf.cpp
16行目
×class InBuf : virtual Buf {
〇class InBuf : virtual public Buf {

22行目
×class OutBuf : virtual Buf {
〇class OutBuf : virtual public Buf {

P318
Twin/Twin.h
6行目の後ろに以下include文を追加挿入
#include <iostream>

P332
Array/BoolArray.h
27行目と28行目の間,BitOfByteRef& operator=(bool b){ 省略 }の定義終了部分とクラス定義終了の};の間に
以下のプログラムを追加。
        BitOfByteRef& operator=(BitOfByteRef BitOfByteRefb) {
            if ((BitOfByteRefb.vec >> BitOfByteRefb.idx) & 1U) {
                vec |= 1U << BitOfByteRefb.idx;
                vec |= 1U << idx;
            }
            else {
                vec &= ~(1U << BitOfByteRefb.idx);
                vec &= ~(1U << idx);
            }
            return *this;
        }

BitOfByteRefbという変数は、任意の名称を使ってよいです。この部分のプログラムがないとその後のメイン関数の使い方

y[3] = y[6] = true;
z[5] = z[7] = true;

でエラーになります。y[3] = y[6]のような代入演算子の引数の形について取り決めがないことになります。プログラムの中身は様々な考え方が適用できますが、自分が考えたのはy[3] = y[6] = true;のような場合、y[6]がtrueやfalseに変更されるので、y[6]の値をy[3]にも反映しつつ、y[6]のtrue or falseの値そのものをy[3]に反映させれば、y[3] = true を実行したのと同じことになるという考え方です。この誤植は、この本の最大規模の間違いのような気がします。


P351
Stack/ArrayStack.h
18行目
× throw Overflow();
〇 throw Stack<Type>::Overflow();

24行目
× throw Empty();
〇 throw Stack<Type>::Empty();


P353
Stack/ListStack.h
3行目の後ろあたりに追加
#include <exception>

39行目
× } catch (const bad_alloc&) {
〇 } catch (const std::bad_alloc&) {

40行目
× throw Overflow();
〇 throw Stack<Type>::Overflow();

46行目
× throw Empty();
〇 throw Stack<Type>::Empty();

P354
Stack/VectorStack.h
24行目
× throw Overflow();
〇 throw Stack<Type>::Overflow();

31行目
× throw Empty();
〇 throw Stack<Type>::Empty();

P371
chap10/vector_assing.cpp
16行目
△ for(vector::size_type i = 0; i < y.size(); i++)
〇 for(vector::size_type i = 0; i < y.size(); i++)

P374
chap10/vector_print
15行目
× for (vector<T, Allocator>::size_type i = 0; i != v.size(); i++)
? for (vector<int>::size_type i = 0; i != v.size(); i++)
size_typeの型にはテンプレートが使えないみたい。つまり、Column10-1全体の説明も怪しいことになります。C++の規格の進化で事情が変わったのか、著者の勘違いなのかは不明です。vector何型であっても、size_typeの型名も何型でも容量は正しく返せそうな気がしますけど、ここはまだまだ調査が必要です。あとでChatGPTにも聞いてみようと思います。

ChatGPTは以下のようにすればテンプレート引数を使ってsize_typeを切り替えることができるとの回答でした。試してみたところ確かにうまく行きました。typenameキーワードを省略してfor文の中に入れ込んでしまうとうまく i の初期化ができないみたいですね。

template <typename T,typename Allocator>
void print_vector(const std::vector<T,Allocator>& v) {
    typename std::vector<T, Allocator>::size_type i = 0;
    std::cout << "{ ";
    for (i = 0; i < (v.size()); i++) {
        std::cout << v[i] << " ";
    }
    std::cout << "}";
}

template <typename T,typename Allocator>
void print_vector(const std::vector<T,Allocator>& v) {
    
    std::cout << "{ ";
    for (typename std::vector<T, Allocator>::size_type i = 0; i < (v.size()); i++) {
        std::cout << v[i] << " ";
    }
    std::cout << "}";
}

でもいいんだって、1行目はtypenameでなくてclassでもいいけど、for文のところのtypenameは変えられません。typenameというのを使うのが現代の主流だそうです。C++03では、本のとおりでも動いたのかもしれません。

P388
chap10/vector_print_it1.cpp
14行目一つ前の正誤関係項目と同じ理由で
× for (vector<T, Allocator>::const_iterator i = v.begin(); i != v.end(); i++)
〇 for (typename vector<T, Allocator>::const_iterator i = v.begin(); i != v.end(); i++)

P397
chap10/vector_print2.cpp
40行目またひとつ前の項目と同じ理由で
× for_each(first, last, put1<std::iterator_traits<InputIterator>::value_type>());
〇 for_each(first, last, put1<typename std::iterator_traits<InputIterator>::value_type>());

またファンクタを受け取るための継承は必要なくなっています。
struct put3 /* : public std::unary_function<const Type&, void> */ {

struct put3<char>/* : public std::unary_function<const char&, void> */ {

struct put3<std::string> /*: public std::unary_function<const std::string&, void> */ {

のように継承を省略してもC++11以降の規格にしたがってプリプロコンパイルリンクをした場合は問題が発生しません。このようなやり方が主流になっているそうです。古き良き歴史を知る上では大事なことかもしれません。

P399
ここでも上の項目のとおり継承が省略できます。どんな型でもどんとこい!って感じで省略できてしまいます。
struct is_even/* : public std::unary_function<const Type&, bool>*/ {

struct plus10/* : public std::unary_function<const Type&, const Type&>*/ {

struct diff/* : public std::binary_function<const Type&, const Type&, Type>*/ {


P426
chap11/string_array_convert.cpp
30行目
△char* p[] = {"PAUL", "X", "MAC"}
〇const char* p[] = {"PAUL", "X", "MAC"}
Microsoft独自の厳密なチェックによりVisualStudio2022では既定の設定ではエラーになります。型"const char*"の値を使用して型"char*"のエンティティを初期化することはできませんというエラーです。

この変更に伴って、
19行目の関数の引数もconstにする必要があります。
△ vector<string> strptary_to_vec(char** p, int n)
〇 vector<string> strptary_to_vec(const char** p, int n)
とする必要があります。関数の引数をそのままにするなら、constでないchar型の2次元ポインタ変数を構築してコピーしないと駄目です。

char** ppchp = new char* [3];
for (int i = 0; i < 3; i++) {
    ppchp[i] = new char[strlen(p[i])];
    strcpy_s(ppchp[i], strlen(p[i]), p[i]);
}
とかね。

P467
chap12/concat.cpp
8行目
× void copy(ifstream&src, ofstream& dst)
〇 void copy(istream& src, ostream& dst)
型"std::ofstream&"の参照(constで修飾されていない)は型"std::ostream"の値では初期化できません。
というエラーになります。std::ifstream は std::istream の派生クラスであり、std::istream への参照を受け取る copy_concat 関数の引数に対して適切に渡すことができます。

あるいは関数テンプレートを使って
template <typename StreamSrc, typename StreamDst>
void copy_concat(StreamSrc& src, StreamDst& dst){
中身のプログラムには変更ないので省略
}
という具合に変更できます。呼び出し側で
copy_concat2(dynamic_cast<std::ifstream&>(cin), dynamic_cast<std::ofstream&>(cout));
ってするとコンパイルはとおりますが実行時エラーで駄目です。現代においては関数の型を変えるしかないですね。


変更した方が良い箇所
P16
Date/Date.cpp
4行目
△ struct tm* local = localtime(&current );
〇 struct tm ptmlocal;
  errno_t error = localtime_s(&ptmlocal, &current);

localtime関数はアンセーフな関数として利用には厳しい警告が発生します。localtime_sを使って予め実体化しておいたstruct tm型の変数を参照型として、localtime_s引数の第一引数として設定すると、その変数に第二引数に設定した時間に関する情報が設定され、受け取ることができます。

P98
chap03/termination.cpp
これも上記と同じ変更がオススメです。

P449
chap12/lasttime.cpp
これも上記と同じ変更がオススメです。

22:00 | Comments (0)

2023年09月01日

_C/C++言語直感的難問

 こんな関数があったとします。

void put_list2(const int pcia[], int in, bool pbfuncfit(int)) {
    bool bflag = false;
    for (int i = 0; i < in; i++) {

        if (pbfuncfit(pcia[i])) {
            cout << "★";
        }
        else {
            cout << " ";
        }
        cout << "a[" << i << "] = " << pcia[i] << "\n";
    }
}

問.pbfuncfitって変数名なのに、後ろに(int)って付いてます。どういうことでしょう?


 はい!シンキングタイム!


 終~了~っ、みじかっ!


 答えは、関数ポインタの間接演算子省略をした表記です。外部から呼び出すときの引数には関数名を指定します。実際に呼び出すときは、サンプルのプログラム内のようにしてint型の引数が必要なものです。関数ポインタの引数であるint型の値も外部から受け取り必要なときは、もう一つ、int型の引数を追加するとかして、うけとらないと駄目ね。


 pbfuncfit(int)って表記だけど、うけとるのは関数名だけなんだってさ。


 わかった人は関数ポインタマスターだね。すごいぜ!忘れてた人は、修行が必要だね。


 ちな、自分はわからなかった。修行が必要な人だぜ。


 ぱっとみなんのこっちゃわからんパターンってこういうことの積み重ねで生まれるんだわ。気をつけないとな。


 再学習し始めたら、わかっていないことだらけ。修行が必要。


 9月はプログラミングの季節だね。9月1日だ。

22:00

2023年08月26日

_C++の再学習ちう

 C++の学びなおしを始めました。Basicのプログラムの打ち込み作業をしつつ、合間で

 さすがに初歩からの学びなおしはだるいので、中級編から始めています。

 クラスで使う仕組みからです。静的メンバ変数・関数・constね。ふんふんって感じ。

 http://www.bohyoh.com/

 ここの本だね。いい本に出合えた感じがする。エピステーメーさんの話がわかるくらいまでにはなりたいね。

22:00 | Comments (0)

2006年06月17日

_VC++な理由。

よねっとはVC++を使う。その理由はVCが優秀だからとか、プログラムのための最高の言語だからとか、そういう意味深な理由は一つもない。

VC++な理由
○工業高校のときにC言語をよく習ったから…そして一番よく理解できたから
○Windowsアプリを作りたいと思ったとき、C言語がVC++だと勘違いしたから。
○Basicは一度も習ったことが無かったので、自分には無理だと信じていたから。
○ポケコンのBasic=VBだと勘違いしていたから…
○ためしにVBを触ってみたが、全く分らなかったから…
○ためしにVCを触ってみたら、やっぱり、全く分らなかったけど、基本的な構文のいくつかは理解できた。
○ネットでちょっと調べたら、C言語派が偉そうだったので、C言語で間違いないと確信してしまったから…もちろんなにが凄いとかそんな理由は理解していない。
○そのころJavaはWeb専門言語JavaScript程度の技術があるとしか思っていなかったから、
○PerlはCGIを書くための言語だと思っていたから(今でもそう思っている。)
○これだけの理由があればもうほかの言語について考える余地がなかったから。
○そして、職場ではやはりC言語ができる人がもてはやされていたというか必要とされていたから…

どうせやるならC言語だなって、そう思った。その判断は今でも間違っていなかったと思っている。JAVAをよくしらない時代遅れの申し子になってしまったが、それでも泣かない。

VC++の誤算
○CとC++は似ても似つかないということ(C++の言語仕様はCを知っていればなんでも理解できるというそういうレベルのものではなかった。)
○そしてC++とVC++でも似ても似つかない。並外れた言語仕様であり、C言語を完璧に理解している程度の知識では何も出来ないということ。
○既に存在しているWinプログラムの世界が思いのほか理解できないということ
○アセンブラの仕様がとてもじゃないが、高校のときにならったようなレベルではなかったということ。

でも、最近はやっとWindowsプログラムの構造や外部実行ファイルやらのとりまきやVCのライブラリ、デバイスの操作をするための手順などがやんわりと掴めて来た。

VCの限界は感じない自分がいる。

VCをやっていて良かったと思うこと、自分がやりたいと思ったことのプログラム
開発に必要なツールキットが大抵C++、つまりVC++のプロジェクトファイルとして
提供されること。Cの歴史が古いせいか、ネットから得られる情報量も十分である
ことに加えて、この10年間のうちにC++の文化が消えるようなことがなかったこと。

そしてC++の理解を深める内にほかの言語も少しヘルプを見ればアプリが同じよう
に作れたこと!PerlもVB(VBA)もActionScriptもNotesScriptもSQLも全てが仕事で
も趣味でも両方で楽しめる。

本来の仕事が、プログラマではない自分だが、技術職とプログラムを両方やれる
ことで感じることの出来る可能性が広がった。19歳とちょっとで初めてPCを買っ
たときから、PCに興味をもってよかったと思う。真剣に向き合ってきて良かった。
インターネットだけ見てるんじゃなくて、無理にドメインとか取得してホームペ
ージを立ち上げてよかった。そして自分の意味のないホームページになにやらよ
くわからないCGIとかを無理やり詰め込んでみたり…

もし、スロットも適当にやってるだけでPCで情報を管理したりしようとか思わな
かったら、本当に人生をスロットに奪われるところだったかもしれない。今の自
分にしかやれないと信じる仕事のスタイルは確立できなかったと思う。

一般人が早急に成果を出すには向いていないところもあるけど、面倒な手続きも
ふんだんに勉強しなければならないちょっと難解なVCという言語を選んでよかっ
たと思う。

さて、君は何をやる?

因みにPerlができるようになるとPHPを覚えたくなくなります。
Perlの言語仕様はC++同様に複雑だった。PHPも同じなのかとか思うと同じことや
るために、もう一つの言語を使おうなんて思えなくなる。今のところPHPを使わな
いと、無理な局面には出会わないよ。あえていうならphpmyadminの設定ファイル
をいじるときにphpのサーバアプリをいれたりする作業が必要になったぐらいかも…

結論
VCである理由は不純。おれは品定めなどしない、流されやすいバカ。