因此istringstream,在初始化时复制字符串的内容,例如
string moo("one two three four");
istringstream iss(moo.c_str());
Run Code Online (Sandbox Code Playgroud)
我想知道是否有办法std::istringstream使用给定c_str的缓冲区而不复制东西.这样,在传递std::istringstream&给istream&作为参数的函数之前,它不必复制大量内存.
我一直在努力做的是转换一些只接受std::ifstream&参数的函数(它们主要是解析器)istream&.我是否必须为此创建自己的istream子类?
从istream中读取的惯用循环是
while (thestream >> value)
{
// do something with value
}
Run Code Online (Sandbox Code Playgroud)
现在这个循环有一个问题:它不会区分循环是由于文件结束还是由于错误而终止.例如,采取以下测试程序:
#include <iostream>
#include <sstream>
void readbools(std::istream& is)
{
bool b;
while (is >> b)
{
std::cout << (b ? "T" : "F");
}
std::cout << " - " << is.good() << is.eof() << is.fail() << is.bad() << "\n";
}
void testread(std::string s)
{
std::istringstream is(s);
is >> std::boolalpha;
readbools(is);
}
int main()
{
testread("true false");
testread("true false tr");
}
Run Code Online (Sandbox Code Playgroud)
第一次调用testread包含两个有效的bool,因此不是错误.第二个呼叫以第三个不完整的bool结束,因此是一个错误.然而,两者的行为是相同的.在第一种情况下,读取布尔值失败,因为没有,而在第二种情况下,它失败,因为它是不完整的,并且在两种情况下都会命中EOF.实际上,上面的程序输出两次相同的行:
TF - 0110
TF - …Run Code Online (Sandbox Code Playgroud) 如何检测线是否为空?
我有:
1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)
我正在用istream r读这个:
int n;
r >> n
Run Code Online (Sandbox Code Playgroud)
我想知道当我到达4到5之间的空间时.我尝试读取为char并使用.peek()来检测\n但是这会检测到数字1之后的\n.以上输入的翻译是:1 \n2 \n3 \n4 \n \n5 \n如果我是正确的...
因为我要操作整数,所以我宁愿把它们作为整数读取而不是使用getline然后转换为int ...
直观地说,从C++规范来看,它看起来好像istream::putback( c )应该总是安排输入缓冲区,以便下一次调用istream::peek()应该读取字符c.这不正确吗?我问,因为随Xcode 4.6发布的最新版本的libc ++似乎并未在所有情况下强制执行此行为 - 特别是当最后一个字符位于EOF时.如果您使用unget()而不是,也是如此putback( c ).
libc ++的行为是正确的,还是我对如何putback()/unget()正确行事的直觉?
考虑这个示例代码,它与libstdc ++一起使用但不与libc ++一起使用(断言失败).
#include <sstream>
#include <cassert>
int main(int argc, const char * argv[])
{
std::istringstream in( "[Test]" );
while( in )
{
int c = in.get();
if( c == ']' )
{
in.putback( c );
assert( in.peek() == c ); // Fails with libc++. Succeeds with libstdc++.
break;
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud) 我正在用C++实现类似shell的程序.它有一个从cin,forks读取并等待孩子的循环.
如果输入是交互式的,或者如果它是从另一个程序传送的,那么这种方法很好.但是,当输入是bash heredoc时,程序会重新读取部分输入(有时是无限期).
我知道子进程继承了父进程的文件描述符,包括共享文件偏移量.但是,这个例子中的孩子没有从cin读取任何东西,所以我认为它不应该触及偏移量.我有点难过为什么会这样.
TEST.CPP:
#include <iostream>
#include <unistd.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
std::string line;
while (std::getline(std::cin, line)) {
pid_t pid = fork();
if (pid == 0) { // child
break; // exit immediately
}
else if (pid > 0) { // parent
waitpid(pid, nullptr, 0);
}
else { // error
perror("fork");
}
std::cout << getpid() << ": " << line << "\n";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我编译如下:
g++ test.cpp -std=c++11
Run Code Online (Sandbox Code Playgroud)
然后我运行它:
./a.out <<EOF …Run Code Online (Sandbox Code Playgroud) 当使用的scanf()和它的变体,该格式说明%i将接受作为十六进制数据(加前缀"0x"为),八进制(前缀"0"),或十进制(无前缀),因此,例如字符串"0x10的","020 "和"16"都转换为十进制值为16的整数.
这可以通过std::istream::operator>>格式化输入完成吗?
使用普通的>> i无I/O操纵器"为0x10"被转换成零(或者更确切地说,前导0,则"×10"的部分不被处理),以及"020",以20 hex,oct和dec操纵行为像%x,%o并%d分别.我正在寻找一个像%i.一样的通用整数输入操纵器.
有趣的是,hex操纵器可能同时接受"0x10"和"10"转换为16位小数.
如果您可能想知道,我正在实现一个表达式求值程序,并且我希望使用C/C++前缀约定允许整数操作数为十六进制,八进制或十进制.当前使用的实现sscanf()会自动使用%i,我很好奇是否可以修改它以使用iostream而无需显式解析数字格式.
我想把一个文件读成一个字符串.我正在寻找有效的方法.
使用固定大小的*char缓冲区
我收到了Tony 的回答是什么创建了一个16kb的缓冲区并读入该缓冲区并附加缓冲区,直到没有其他内容可读.我理解它是如何工作的,我发现它非常快.我不明白的是,在答案的评论中,据说这种方式将所有内容复制两次.但据我所知,它只发生在内存中,而不是发生在磁盘上,所以它几乎是不可察觉的.它是从缓冲区复制到内存中的字符串的问题吗?
使用istreambuf_iterator
我收到的另一个答案是使用istreambuf_iterator.代码看起来美观而且极小,但速度极慢.我不知道为什么会这样.为什么那些迭代器这么慢?
使用memcpy()
对于这个问题,我收到的评论是我应该使用memcpy(),因为它是最快的本机方法.但是如何将memcpy()与字符串和ifstream对象一起使用?是不是ifstream应该使用自己的读取功能?为什么使用memcpy()破坏可移植性?我正在寻找与VS2010以及GCC兼容的解决方案.为什么memcpy()不适用于那些?
+还有其他任何有效的方法吗?
对于小的<10 MB二进制文件,你推荐什么,我使用什么shell?
(我不想将这个问题分成几部分,因为我对如何将ifstream读入字符串的不同方式之间的比较更感兴趣)
如果我想要一个缓冲区read()的内容std::istream,我将不得不首先了解有多少数据可用来知道缓冲区的大小.为了从istream中获取可用字节数,我目前正在做这样的事情:
std::streamsize available( std::istream &is )
{
std::streampos pos = is.tellg();
is.seekg( 0, std::ios::end );
std::streamsize len = is.tellg() - pos;
is.seekg( pos );
return len;
}
Run Code Online (Sandbox Code Playgroud)
同样地,由于std :: istream :: eof()不是一个非常有用的基金AFAICT,为了找出是否istream得到指针在流的末尾,我这样做:
bool at_eof( std::istream &is )
{
return available( is ) == 0;
}
Run Code Online (Sandbox Code Playgroud)
我的问题:
有没有更好的方法来获取可用字节数istream?如果不是在标准库中,也许在boost中?
首先,这与此没有重复是否已存在COM互操作IStream的包装类?因为我需要在另一个方向实施.我需要创建一个从IO.Stream到IStream的IStream实现.但在我开始尝试这样做之前,想问一下是否有人知道已经存在的实施或任何关于此的文章.我在.net框架中找不到任何东西,谷歌只给了我从IStream到IO.Stream的实现结果.那么有人对我有一个很好的建议吗?我真的不知道如何开始,因为第一个成员(克隆 - >创建一个新的流对象,它引用与原始流相同的字节,但提供一个单独的搜索指针指向这些字节)让我很麻烦.我不知道如何基于IO.Stream做到这一点.
为用户定义的类型创建格式化输出时,通常需要定义自定义格式标记.例如,如果自定义字符串类可以选择在字符串周围添加引号,那将是很好的:
String str("example");
std::cout << str << ' ' << squotes << str << << ' ' << dquotes << str << '\n';
Run Code Online (Sandbox Code Playgroud)
应该产生
example 'example' "example"
Run Code Online (Sandbox Code Playgroud)
很容易创建操纵器来更改格式化标志本身:
std::ostream& squotes(std::ostream& out) {
// what magic goes here?
return out;
}
std::ostream& dquotes(std::ostream& out) {
// similar magic as above
return out;
}
std::ostream& operator<< (std::ostream& out, String const& str) {
char quote = ????;
return quote? out << quote << str.c_str() << quote: str.c_str();
}
Run Code Online (Sandbox Code Playgroud)
...但是操纵器如何存储哪些引号应该与流一起使用,然后让输出操作符检索值?