C++ iostream 実装例 その 1
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
]
開始行:
[[C++のiostream]]
* C++ iostream 実装例 その 1 [#j5fc2ad7]
C++ の iostream 実装例として、効率無視の超簡単、超手抜き ...
iostream 化を示す。実用性というよりは、最低限実装すべき機...
(私が忘れた場合に備えての)メモとして残しておくものであ...
** 何をすればよいか [#g7de8cc1]
C++ の iostream は(効率を無視すれば)実装が極めて簡単に...
構造になっている。
極端なことを言えば、必要なのは
streambuf の派生 class を作る
ことだけである。
実装のために iostream class の内容を知る必要は全く無いし、
iostream の派生 class を作る必要すら無い。
streambuf class の派生 class を作り、その object の
streambuf 部分の pointer を iostream の constructor に渡...
それだけで iostream として使える。
(具体的には次節 [[C++ iostream 実装例 その 2]] 参照)。
** 最小限実装すべきもの [#jdcd6647]
streambuf から派生させた class で実装する
必要があるのは、以下の4つの protected member
関数である。(詳しくは、[[C++のiostream]] に示してある
私の実装資料を参照のこと。)
- virtual int underflow(void);
- virtual int uflow(void);
- virtual int overflow(int c = std::char_traits::eof());
- virtual int sync(void);
各関数の果たすべき役割を簡単に説明すると、
- underflow() は読み出し位置を進めずに1文字読み出す関数、
- uflow() は1文字読み出した後、読み出し位置を1文字分進め...
- overflow(int c) は c を書き込み位置に書き出し、書き込み...
- sync() は未出力の書き込み buffer の中身を出力先に送り出...
である。
overflow(int c) で常に出力先へ出力するのであれば、sync() ...
必要無い。
** 実装例 [#sce26e8d]
というわけで、実装してみよう。実装するのは、TCP/IP の con...
対して行おう。長い source code は見るのが鬱陶しいので、
TCP/IP の connection を張るところまでは済んでいるものとし...
constructor にその socket を渡すものとしよう。
member 変数としては、constructor で渡される socket descri...
保持しておく m_socket と、上記 underflow() と uflow() を...
ための1文字分の(先読み)buffer m_gpend_char と
buffer 内に文字があるかどうかを示す flag m_gpend を用意す...
(g は get 用の意味、std::streambuf 内の命名法を真似てみ...
// tcpbuf.h
#ifndef TCPBUFFER_H_INCLUDED
#define TCPBUFFER_H_INCLUDED
#include <streambuf>
namespace mynetlibrary
{
class tcpbuffer :
public std::streambuf
{
public:
tcpbuffer(int sock);
virtual ~tcpbuffer(void);
int state(void) const;
protected:
virtual int underflow(void);
virtual int uflow(void);
virtual int overflow(int c = std::char_traits<char>::eo...
virtual int sync(void);
protected:
int m_socket;
bool m_gpend;
int m_gpend_char;
};
} // namespace mynetlibrary
#endif // TCPBUFFER_H_INCLUDED
で、定義(source)。ここで、socket descriptor をどういう...
少し悩むところである。ここでは一応 thread で使う安全性も
考えて dup() を使って copy しておく。従って、呼び出し側で...
それ以上必要無ければ、close() しておくこと。
なお、以下の実装で、buf[] の size を 1 ではなく 2 として...
大きさ 1 の"配列"は気持ち悪いという筆者の主観もあるが、も...
text mode での CR LF の扱いを将来入れたくなるかも知れない...
思惑も働いている。長くなるので載せないが、実際やってみた...
// tcpbuf.cpp
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "tcpbuf.h"
namespace mynetlibrary
{
tcpbuffer::tcpbuffer(int sock)
{
m_gpend = false;
m_gpend_char = std::char_traits<char>::eof();
m_socket = ::dup(sock);
}
tcpbuffer::~tcpbuffer(void)
{
if(m_socket != -1)
::close(m_socket);
}
int
tcpbuffer::state(void) const
{
if(m_socket == -1)
return -1;
return 0;
}
int
tcpbuffer::underflow(void)
{
unsigned char buf[2];
// Get the next character. The getpoint does not move.
if(m_gpend)
return m_gpend_char;
if(m_socket == -1)
return std::char_traits<char>::eof();
if(::recv(m_socket, buf, 1, 0) != 1)
return std::char_traits<char>::eof();
int c = (int)buf[0];
m_gpend = true;
m_gpend_char = (c & 255);
return m_gpend_char;
}
int
tcpbuffer::uflow(void)
{
int c = underflow();
m_gpend = false;
return c;
}
int
tcpbuffer::overflow(int c)
{
if(c == std::char_traits<char>::eof())
return 0;
if(m_socket == -1)
return std::char_traits<char>::eof();
unsigned char buf[2];
buf[0] = (unsigned char)(c & 255);
if(::send(m_socket, buf, 1, 0) != 1)
return std::char_traits<char>::eof();
return c;
}
int
tcpbuffer::sync(void)
{
return 0;
}
} // namespace mynetlibrary
次節 "[[C++ iostream 実装例 その 2]]" では、この実装を i...
使う例を示そう。
** Windows での注意 [#w83daa5e]
Windows 用にするには、
- Winsock の load/unload
- dup() を DuplicateHandle で実装
- close() を closesocket() に変更
する必要がある。
更に型を正しくするには、
- socket descriptor は int ではなく SOCKET
- socket descriptor の不正を表す値は -1 ではなく INVALID_...
- send()、recv() の失敗を表す戻り値は -1 ではなく、SOCKET...
である(なお、実態は singned/unsigned の違いはあったかも...
実は同じ)。
終了行:
[[C++のiostream]]
* C++ iostream 実装例 その 1 [#j5fc2ad7]
C++ の iostream 実装例として、効率無視の超簡単、超手抜き ...
iostream 化を示す。実用性というよりは、最低限実装すべき機...
(私が忘れた場合に備えての)メモとして残しておくものであ...
** 何をすればよいか [#g7de8cc1]
C++ の iostream は(効率を無視すれば)実装が極めて簡単に...
構造になっている。
極端なことを言えば、必要なのは
streambuf の派生 class を作る
ことだけである。
実装のために iostream class の内容を知る必要は全く無いし、
iostream の派生 class を作る必要すら無い。
streambuf class の派生 class を作り、その object の
streambuf 部分の pointer を iostream の constructor に渡...
それだけで iostream として使える。
(具体的には次節 [[C++ iostream 実装例 その 2]] 参照)。
** 最小限実装すべきもの [#jdcd6647]
streambuf から派生させた class で実装する
必要があるのは、以下の4つの protected member
関数である。(詳しくは、[[C++のiostream]] に示してある
私の実装資料を参照のこと。)
- virtual int underflow(void);
- virtual int uflow(void);
- virtual int overflow(int c = std::char_traits::eof());
- virtual int sync(void);
各関数の果たすべき役割を簡単に説明すると、
- underflow() は読み出し位置を進めずに1文字読み出す関数、
- uflow() は1文字読み出した後、読み出し位置を1文字分進め...
- overflow(int c) は c を書き込み位置に書き出し、書き込み...
- sync() は未出力の書き込み buffer の中身を出力先に送り出...
である。
overflow(int c) で常に出力先へ出力するのであれば、sync() ...
必要無い。
** 実装例 [#sce26e8d]
というわけで、実装してみよう。実装するのは、TCP/IP の con...
対して行おう。長い source code は見るのが鬱陶しいので、
TCP/IP の connection を張るところまでは済んでいるものとし...
constructor にその socket を渡すものとしよう。
member 変数としては、constructor で渡される socket descri...
保持しておく m_socket と、上記 underflow() と uflow() を...
ための1文字分の(先読み)buffer m_gpend_char と
buffer 内に文字があるかどうかを示す flag m_gpend を用意す...
(g は get 用の意味、std::streambuf 内の命名法を真似てみ...
// tcpbuf.h
#ifndef TCPBUFFER_H_INCLUDED
#define TCPBUFFER_H_INCLUDED
#include <streambuf>
namespace mynetlibrary
{
class tcpbuffer :
public std::streambuf
{
public:
tcpbuffer(int sock);
virtual ~tcpbuffer(void);
int state(void) const;
protected:
virtual int underflow(void);
virtual int uflow(void);
virtual int overflow(int c = std::char_traits<char>::eo...
virtual int sync(void);
protected:
int m_socket;
bool m_gpend;
int m_gpend_char;
};
} // namespace mynetlibrary
#endif // TCPBUFFER_H_INCLUDED
で、定義(source)。ここで、socket descriptor をどういう...
少し悩むところである。ここでは一応 thread で使う安全性も
考えて dup() を使って copy しておく。従って、呼び出し側で...
それ以上必要無ければ、close() しておくこと。
なお、以下の実装で、buf[] の size を 1 ではなく 2 として...
大きさ 1 の"配列"は気持ち悪いという筆者の主観もあるが、も...
text mode での CR LF の扱いを将来入れたくなるかも知れない...
思惑も働いている。長くなるので載せないが、実際やってみた...
// tcpbuf.cpp
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "tcpbuf.h"
namespace mynetlibrary
{
tcpbuffer::tcpbuffer(int sock)
{
m_gpend = false;
m_gpend_char = std::char_traits<char>::eof();
m_socket = ::dup(sock);
}
tcpbuffer::~tcpbuffer(void)
{
if(m_socket != -1)
::close(m_socket);
}
int
tcpbuffer::state(void) const
{
if(m_socket == -1)
return -1;
return 0;
}
int
tcpbuffer::underflow(void)
{
unsigned char buf[2];
// Get the next character. The getpoint does not move.
if(m_gpend)
return m_gpend_char;
if(m_socket == -1)
return std::char_traits<char>::eof();
if(::recv(m_socket, buf, 1, 0) != 1)
return std::char_traits<char>::eof();
int c = (int)buf[0];
m_gpend = true;
m_gpend_char = (c & 255);
return m_gpend_char;
}
int
tcpbuffer::uflow(void)
{
int c = underflow();
m_gpend = false;
return c;
}
int
tcpbuffer::overflow(int c)
{
if(c == std::char_traits<char>::eof())
return 0;
if(m_socket == -1)
return std::char_traits<char>::eof();
unsigned char buf[2];
buf[0] = (unsigned char)(c & 255);
if(::send(m_socket, buf, 1, 0) != 1)
return std::char_traits<char>::eof();
return c;
}
int
tcpbuffer::sync(void)
{
return 0;
}
} // namespace mynetlibrary
次節 "[[C++ iostream 実装例 その 2]]" では、この実装を i...
使う例を示そう。
** Windows での注意 [#w83daa5e]
Windows 用にするには、
- Winsock の load/unload
- dup() を DuplicateHandle で実装
- close() を closesocket() に変更
する必要がある。
更に型を正しくするには、
- socket descriptor は int ではなく SOCKET
- socket descriptor の不正を表す値は -1 ではなく INVALID_...
- send()、recv() の失敗を表す戻り値は -1 ではなく、SOCKET...
である(なお、実態は singned/unsigned の違いはあったかも...
実は同じ)。
ページ名: