C++第3版 8章 練習問題解答
-
8.1 , 8.2 , 8.3 ,
8.4 , 8.5 , 8.6 ,
8.7 , 8.8 , 8.9 ,
8.10 , 8.11
目次へ戻る
#include <list>
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
#pragma warning(disable : 4786)
namespace stringList {
typedef vector<string> LType;
typedef LType::iterator Iterator;
LType lst;
Iterator begin(){return lst.begin();}
Iterator end(){return lst.end();}
void sort(){std::sort(begin(),end());}
void reverse(){std::reverse(begin(),end());}
void push_back(const string& s){lst.push_back(s);}
}
namespace L = stringList;
int main()
{
L::push_back("Pascal");
L::push_back("C");
L::push_back("Fortran");
L::push_back("ALGOL");
L::push_back("Perl");
L::push_back("Java");
L::push_back("COBOL");
L::push_back("Smalltalk");
L::Iterator i;
L::sort();
for (i=L::begin();i!=L::end();++i)
cout << *i << " ";
cout << endl;
L::reverse();
for (i=L::begin();i!=L::end();++i)
cout << *i << " ";
cout << endl;
}
|
Iterator を iterator としたいが、コンパイルできない。
pragma は例によって VC を黙らせるため。
namespace test {
#include <stdio.h>
}
int main()
{
test::printf("ok\n");
}
|
namespace calc で括って、呼出し側で calc:: をつければよい。
#include <iostream>
using namespace std;
void f(){throw "test";}
int main()
{
try {f();}
catch (char* s) {cout << s << endl;}
}
|
#include <iostream>
using namespace std;
void g(int,int);
void f(int l, int i = -1)
{
cout << "enter f " << i << endl;
if (i < 0) g(l,10);
else if (i) {
g(l,i-1);
if (i == l) throw "error f";
}
}
void g(int l,int i)
{
cout << "enter g " << i << endl;
if (i > 0) f(l,i-1);
if (i == l) throw "error g";
}
int main()
{
try {f(3);}
catch (char* s) {cout << s << endl;}
try {f(4);}
catch (char* s) {cout << s << endl;}
}
|
時間計測用のクラスのヘッダ
// etime.h
#include <sys/types.h>
class CETime {
time_t m_time;
unsigned short m_millitm;
public:
inline void Reset();
inline double Sec()const;
CETime(){Reset();}
};
|
時間計測用のクラスのソース
// etime.cpp
#include "etime.h"
#include <sys/timeb.h>
void CETime::Reset()
{
timeb tb;
ftime(&tb);
m_time = tb.time;
m_millitm = tb.millitm;
}
double CETime::Sec()const
{
timeb tb;
ftime(&tb);
return double(tb.time - m_time) + 0.001*(tb.millitm - m_millitm);
}
|
解答の本体のソース
#include "etime.h"
#include <string>
#include <iostream>
using namespace std;
void g(int,int);
void f(int l, int i = -1)
{
string s = "dumy"; // string 変数
if (i < 0) g(l,10);
else if (i) {
g(l,i-1);
if (i == l) throw "error f";
}
}
void g(int l,int i)
{
string s = "dumy"; // string 変数
if (i > 0) f(l,i-1);
if (i == l) throw "error g";
}
int main()
{
int i,j, k[] = {10,0,-1}, n = 100000;
CETime e;
for (j=0;j<3;++j) {
e.Reset();
for (i=0;i<n;++i) {
try {f(k[j]);}
catch (char*) {if (i%(n/10)==0) printf(".");}
}
cout << endl << e.Sec() << endl;
}
}
|
CETime は、時間計測用のクラス。
string 変数 | 1回目 | 2回目 | 3回目 |
なし | 6.3 | 5.8 | 0.3 |
あり | 16.5 | 21.0 | 5.8 |
上表は、1回目がすぐ抜ける時の時間(秒)、2回目が最後に抜ける時の時間、
3回目が例外を発生しない時の時間を表している。
関数 f と g の string 変数がないとき、1回目と2回目の時間は、
ほぼ同じであるから、ローカル変数がないときは、例外のコストは深さに依存しないと思われる。
逆に、デストラクタを持つローカル変数があるときは、
深いところで例外の発生する方がコストがかかるようである。
また、「ローカル変数の初期化+後処理」と「例外」のコストは、このケースでは同じぐらいである。
エラーが起きた時、Lexer::get_token で改行まで読み飛ばそうとしている。
しかし、get_token は、正常な入力を期待しており、エラーの時に呼出すと改行を読み飛ばす危険性がある。
etime.h は8.6を参照のこと。
#include "etime.h"
#include <iostream>
using namespace std;
char* f(int i)
{
if (i) throw "error";
return 0;
}
int main()
{
int i,j, n = 100000;
CETime e;
for (j=0;j<2;++j) {
e.Reset();
for (i=0;i<n;++i) {
try {f(j);}
catch (char*) {if (i%(n/10)==0) printf(".");}
}
cout << endl << e.Sec() << endl;
}
}
|
値を返す方は、0.05 秒、例外は 6.5 秒であった。
文法違反では、各関数が 0 を返すように設計されており、
例外を扱いやすい形にはなってないので省略する。
自信なし。
#include <limits>
using namespace std;
struct EOverFlow {};
struct EUnderFlow {};
double plus(double i,double j)
{
double d = i+j;
if (numeric_limits<double>::infinity() == d)
throw EOverFlow();
return d;
}
double minus(double i,double j)
{
double d = i-j;
if (numeric_limits<double>::infinity() == d)
throw EOverFlow();
return d;
}
double multiply(double i,double j)
{
double d = i*j;
if (numeric_limits<double>::infinity() == d)
throw EOverFlow();
if (i != 0 && j != 0 && d == 0)
throw EUnderFlow();
return d;
}
double divide(double i,double j)
{
double d = i/j;
if (numeric_limits<double>::infinity() == d)
throw EOverFlow();
if (i != 0 && d == 0)
throw EUnderFlow();
return d;
}
|
8.9と同じ理由で省略する。
前章へ
目次へ
次章へ