このように出力用に「空の」ストリームを作成できないのはなぜですか
_std::ostream out;
_
?
この行は、Linuxの_clang 3.4
_と_gcc 4.8.1
_の両方で明らかに違法です。Linuxでは_libstdc++
_を使用しているので、理由がわかりません。私がしたいようにそれを使用しますか?代わりに、_std::ofstream out;
_は100%OKであることに注意してください。私はこの背後にある論理を理解していません。作成後にこのバッファを使用して、copyfmt
を持つ他のバッファと共通のバッファを共有できるため、_std::ostream
_を何かに初期化する必要がないことを考えると、これはさらに奇妙です。有用なオブジェクトの作成からすぐに。
これから逸脱しないでください。stringstreams
は必要ありません。私がしなければならないことと、それらが提供するメソッドとプロパティのために、ios
ストリームが必要です。
私もそれを理解していないことを認めます。 std::istream
のデフォルトのコンストラクターがまったく見つかりません。std::ios_base
の動作がおかしいため、双方向ストリームを作成する場合は、コンストラクターが必要だと思います。コンストラクターはnot initializeを実行します。ただし、派生クラスはコンストラクターで明示的にstd::ios_base::init
を呼び出す必要があります。多重継承が関係する場合(つまり、クラスがstd::istream
とstd::ostream
の両方から派生する双方向IO)、最も派生したクラスのみがstd::ios_base::init
を呼び出すことを期待します。 (std::iostream
では、std::ios_base::init
は2回呼び出されます。)実際、標準で検索する前に、デフォルトのコンストラクターは保護されていると答えようとしていました。これは、std::ios_base::init
を呼び出さず、直接使用するためではなく、派生クラスは、初期化されていないストリームになります。
とにかく、あなたの当面の問題には簡単な解決策があります:
std::ostream out( NULL );
また、後でシンクを設定する必要がある関数は、rdbuf()
ではなく、非constバージョンのcopyfmt()
です。 rdbuf()
はポインタを読み取ってstreambuf
に設定するために使用され、copyfmt()
はフォーマットフラグをコピーしますが、notポインタに触れますstreambuf
へ。
したがって、次のようなことができます。
std::ostream out( NULL );
// ...
std::filebuf fileBuffer;
if ( filenameGiven ) {
fileBuffer.open( filename.c_str(), std::ios_base::out );
}
if ( fileIsOpen() ) {
out.rdbuf( &fileBuffer );
} else {
out.rdbuf( std::cout.rdbuf() );
}
(私はこれを頻繁に行います。実際、ファイルに出力するかstd::cout
に出力するかを前もって知らなかったときは、通常のイディオムだと思いました。)
編集:
さらに別の修正:非constバージョンのrdbuf
はclear()
を呼び出すので、そうする必要はありません。 (私はclear()
を呼び出さずにこれを行ったことを知っていましたが、それを見たときinit
set badbit
...)
とにかく:要約は次のとおりです。通常、有効なstreambufへのポインターをstd::ostream
のコンストラクターに渡すことが望ましいですが、できない場合は、nullポインターを渡し、後でrdbuf()
。そして、そうでないと言う答えは単に間違っています。
std::ostream
は概念的に抽象的であり、作成することは想定されていません(ただし、詳細については他の回答を参照してください)。
std::stringstream
は、std::ostream
から派生しているため、すべてを提供します。これは、たとえば関数の引数など、std::ostream&
が必要な場所であればどこでも、std::stringstream
オブジェクトを渡すことができることも意味します。
あなたは「有用であるために[それ]を初期化する必要はない[...]」と言います。それはまったく意味がありません。初期化されていないanythingは使用できません:int
sでも。
std::basic_ostream
のdefaultコンストラクターはprotected
です。これは、std::basic_ostream
とデフォルトを設定せずにstd::basic_streambuf
を作成することは一般的に意味がないためです。コンストラクターは実際には初期化を行いません(以下を参照)。ただし、ストリームバッファを引数として取る別のコンストラクタがあります。まだ何もするように設定されていないstd::ostream
が本当に必要な場合は、そのコンストラクターを使用できます。
std::ostream out(0);
このstd::ostream
には、std::ios::rdbuf()
を使用してストリームバッファが設定されるまで、std::ios_base::badbit
が設定されます。
std::ostream
のデフォルトコンストラクターがprotected
である根本的な理由は、実際には意図的に何も役に立たないためです。特に、[さらに派生したクラスから]このコンストラクターを呼び出すと、ストリームバッファーがnot初期化されません。標準では明示的に動作が義務付けられていません。つまり、デフォルトコンストラクターは、デフォルトコンストラクターの生成の動作を暗黙的に持っています(または、C++ 2011では、= default
を使用して定義されているかのように)。ストリームバッファを初期化するには、std::ios::init()
を呼び出す必要があります。この奇妙な動作の理由は、さらに派生したクラスstd::iostream
のオブジェクトを構築すると、std::ios
オブジェクトが2回初期化され、1回はstd::ostream
を介して、もう1回はstd::istream
を介して初期化されるためです。
他のいくつかの回答が示唆しているのとは異なり、std::ostream
はまったく抽象的ではありません。実際、とにかくvirtual
関数は1つしかなく、それがデストラクタです(virtual
であるデストラクタはたまたま私のせいです。それが本当に良いアイデアだとは完全には確信していません。それを強制するために)。
stringstream
はios
ストリームです。
しかし、あなたの質問について:
ostream
はどこかに書き込みます。あなたが宣言した場合
std::ostream out;
out << "Hello, world!"<<std::endl
"Hello, world!"
はどこかに書く必要があります。しかしここで?これは、特定のostream
ごとの実装によって異なります。はい、バッファがありますが、そのバッファは特定の実装にも依存します。
それで、あなたが「私はostream
が欲しい」と言うとき、私は尋ねなければなりません-何かを書くもの...どこに?
あなたの答えがあれば、それはあなたが使用する必要があるostream
の特定のインスタンス/実装を教えてくれます。
Std :: ostreamは、一般化されたストリームクラスです。そのため、ストリーミング先を知る方法がありません。これが、一般化されたクラスを持つことの全体的なポイントです。
データをストリームに送信する場合、実際にはデータ自体は保存されません。関連するバッファに転送するだけです。これを考慮に入れると、このバッファーを割り当てずに一般化ストリームを作成しても意味がありません。一般化クラスは空の一般化バッファーを作成できないためです。 (バッファー自体は具象型のバッファーである必要があります。これは、パブリックコンストラクターがまったくない一般化されたバッファーstd :: treambufを見ても理解できます)
これを特定のタイプのバッファーを持つストリームであるstd :: ofstreamと比較すると、ofstreamが使用するバッファーの種類を知ることができるようになり、デフォルトのstd :: filebufをインスタンス化できるようになりました。
あなたの具体的な問題を解決するために。
最初に必要なタイプのバッファーを作成してから、バッファーをパラメーターとして使用して一般化されたstd :: ostreamを作成します。その後、std :: filebuf :: open()を使用してファイルに接続できます。
例:
std::filebuf fileBuffer;
std::ostream myOstream(&fileBuffer); // Hand over the address of the fileBuffer
fileBuffer.open("filename.txt", std::ios::out);
myOstream << "Text to file";