为什么我不能像我这样为我的输出创建一个“空”流
std::ostream out;
这行显然是非法的clang 3.4
和gcc 4.8.1
在linux下libstdc++
,我真的不明白为什么,我的意思是为什么我不能只创建一个流无处可去,像我想的那样使用它?注意std::ofstream out;
是100%确定的。我只是没有得到这背后的逻辑。
如果您考虑在创建之后我可以使用此缓冲区并与copyfmt
的其他缓冲区共享公共缓冲区,那么这甚至更奇怪,因此我不需要将std::ostream
初始化为正确的从对象的创建到有用。
请不要偏离这一点,我不需要stringstreams
,因为我必须做的事情以及他们提供的方法和属性,我需要ios
个流。
答案 0 :(得分:12)
我承认我也不理解。我找不到任何东西
std::istream
的默认构造函数,我想
如果你想创建一个双向流,你会想要一个,
因为std::ios_base
工作的奇怪方式:
构造函数不初始化任何东西,但派生的
class必须在其中明确调用std::ios_base::init
构造函数。当涉及多重继承时(即
双向IO,类派生自两者
std::istream
和std::ostream
),我只期望最多
派生类来调用std::ios_base::init
。 (在
std::iostream
,std::ios_base::init
将被调用两次。)
事实上,在查看标准之前,我就是这样做的
回答默认构造函数是受保护的,因为它
没有打电话给std::ios_base::init
,而是直接使用它
而不是派生类,会导致未初始化
流。
无论如何,你的直接问题有一个简单的解决方案:
std::ostream out( NULL );
另外:稍后设置其接收器所需的功能是
{const rdbuf()
的非常量版本,而不是copyfmt()
。 rdbuf()
是
用于读取和设置指向streambuf
的指针,
copyfmt()
复制格式化标记,但不触摸
指向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
。)
编辑:
又一次更正:rdbuf
的非常量版本调用clear()
,
所以你不必。 (我知道我没有打电话给clear()
就这样做了,但是
当我看到init
设置badbit
...)
无论如何:摘要是:通常更喜欢将指针传递给有效的
streambuf到std::ostream
的构造函数,但如果你不能,那就是。{
完全有效传递空指针,稍后使用设置有效指针
rdbuf()
。而另外说的答案是完全错误的。
答案 1 :(得分:9)
std::ostream
在概念上是抽象的 - 你不应该创建它们(但有关详细信息,请参阅其他答案)。
std::stringstream
为您提供std::ostream
所做的一切,因为它源自它。这也意味着您想要std::ostream&
的任何地方,例如在函数参数中,您可以传递std::stringstream
对象。
你说“没有必要初始化[...]有用”。这毫无意义。您不能使用尚未初始化的任何:偶数int
s。
答案 2 :(得分:6)
std::basic_ostream
的默认构造函数为protected
,因为创建std::basic_ostream
而不设置其std::basic_streambuf
通常没有任何意义并且默认构造函数实际上不进行任何初始化(见下文)。但是,有另一个构造函数将流缓冲区作为参数。如果你真的需要一个std::ostream
但没有设置任何东西,你可以使用那个构造函数:
std::ostream out(0);
此std::ostream
将设置std::ios_base::badbit
,直到使用std::ios::rdbuf()
设置流缓冲区。
std::ostream
默认构造函数为protected
的根本原因是它实际上故意不做任何有用的事情!特别是,调用此构造函数[来自另一个派生类]将不初始化流缓冲区:标准不明确强制任何行为,即默认构造函数隐式地具有行为生成默认构造函数(或者,在C ++ 2011中,就好像它是使用= default
定义的那样)。要初始化流缓冲区,需要调用std::ios::init()
。这种奇怪行为的原因是构造进一步派生类std::iostream
的对象会将std::ios
对象初始化两次,一次通过std::ostream
,一次通过std::istream
。
与其他一些答案不同,std::ostream
根本不是抽象的。事实上,它只有一个virtual
函数,它是析构函数(析构函数virtual
恰好是我的错;我并不完全相信强迫它是一个好主意这一点)。
答案 3 :(得分:2)
stringstream
是一个ios
信息流。
但关于你的问题:
ostream
在某处写。如果你宣布
std::ostream out;
out << "Hello, world!"<<std::endl
"Hello, world!"
应写在某处。但是哪里?这取决于每个特定ostream
的实施情况。是的,有一个缓冲区,但该缓冲区还取决于具体的实现。
所以,当你说“我想要一个ostream
”时,我不得不问 - 一个写东西......到哪里?
根据您的回答,这将告诉我您需要使用ostream
的具体实例/实现。
答案 4 :(得分:2)
std :: ostream是一个通用的流类。因为它无法知道流向什么,这就是拥有广义类的重点。
当您将数据发送到流时,它实际上并不存储数据本身。它只是将其传递给相关的缓冲区。考虑到这一点,创建一个通用流而不将此缓冲区分配给它是没有意义的,因为通用类不能创建一个空的通用缓冲区。 (缓冲区本身需要是具体类型的缓冲区,通过查看根本没有公共consstructor的通用缓冲区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";