istreambuf_iterator何时引发异常
When does an istreambuf_iterator throw an exception?
istreambuf_iterator何时引发异常? 当基础流尝试读取目录时,我收到异常,但在其他情况下没有。 具体来说,我从Jan-Philip Gehrcke的博客中抓取了脚本readfile_tests.sh
,并对其进行了轻微修改:
$ cat readfile_tests.sh
#!/bin/bash
COMPILATION_SOURCE=$1
NE_FILE="na"
EMPTY_FILE="empty_file"
ONE_LINE_FILE="one_line_file"
INVALID_LINE_FILE="invalid_line_file"
FILE_READ="file_read"
FILE_WRITTEN="file_written"
FILE_DENIED="/root/.bashrc"
DIR="dir"
# compile test program, resulting in a.out executable
g++ -std=c++11 $COMPILATION_SOURCE
# create test files / directories and put them in the desired state
touch $EMPTY_FILE
if [[ ! -d $DIR ]]; then
mkdir $DIR
fi
echo "rofl" > $ONE_LINE_FILE
echo -ne "validlineninvalidline" > $INVALID_LINE_FILE
echo "i am opened to read from" > $FILE_READ
python -c 'import time; f = open("'$FILE_READ'"); time.sleep(4)' &
echo "i am opened to write to" > $FILE_WRITTEN
python -c 'import time; f = open("'$FILE_WRITTEN'", "a"); time.sleep(4)' &
# execute test cases
echo "******** testing on non-existent file.."
./a.out $NE_FILE
echo
echo "******** testing on empty file.."
./a.out $EMPTY_FILE
echo
echo "******** testing on valid file with one line content"
./a.out $ONE_LINE_FILE
echo
echo "******** testing on a file with one valid and one invalid line"
./a.out $INVALID_LINE_FILE
echo
echo "******** testing on a file that is read by another process"
./a.out $FILE_READ
echo
echo "******** testing on a file that is written to by another process"
./a.out $FILE_WRITTEN
echo
echo "******** testing on a /root/.bashrc (access should be denied)"
./a.out $FILE_DENIED
echo
echo "******** testing on a directory"
./a.out $DIR
然后,我在以下程序上运行了测试
$ cat test.cpp
#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
#include <string>
int main(int argc, char* argv[]) {
if(argc != 2) {
std::cerr << "Provide one argument" << std::endl;
return EXIT_FAILURE;
}
std::ifstream fin(argv[1]);
std::istreambuf_iterator <char> eos;
std::istreambuf_iterator <char> fin_it(fin.rdbuf());
std::string str;
try {
std::copy(fin_it,eos,std::back_inserter(str));
} catch(...) {
perror("Error");
throw;
}
std::cout << str;
return EXIT_SUCCESS;
}
运行它后,我收到了以下结果:
$ ./readfile_tests.sh test.cpp
******** testing on non-existent file..
******** testing on empty file..
******** testing on valid file with one line content
rofl
******** testing on a file with one valid and one invalid line
validline
invalidline
******** testing on a file that is read by another process
i am opened to read from
******** testing on a file that is written to by another process
i am opened to write to
******** testing on a /root/.bashrc (access should be denied)
******** testing on a directory
Error: Is a directory
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_filebuf::underflow error reading the file
./readfile_tests.sh: line 51: 22563 Aborted ./a.out $DIR
这些结果对我来说很奇怪,因为在读取目录测试时抛出了异常,但在尝试读取/root/.bashrc
时没有抛出异常。 因此,istreambuf_iterator何时抛出异常? 万一重要,我使用gcc version 4.7.3
.
编辑 1
是的,打开目录进行阅读是不标准的和不好的。 同时,我需要正确捕获此案。 根据下面的注释,这是一段尝试从目录中读取的代码:
#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
#include <string>
void withIterators() {
std::ifstream fin("mydirectory");
if(!fin.is_open())
perror("Error opening file");
std::istreambuf_iterator <char> eos;
std::istreambuf_iterator <char> fin_it(fin.rdbuf());
std::string str;
try {
std::copy(fin_it,eos,std::back_inserter(str));
} catch(...) {
perror("Error reading file");
}
}
void noIterators() {
std::ifstream fin("mydirectory");
if(!fin.is_open())
perror("Error opening file");
std::string line;
while(getline(fin,line)) {}
if(fin.bad())
perror("Error reading file");
}
int main() {
withIterators();
noIterators();
}
运行后,我们收到输出:
Error reading file: Is a directory
Error reading file: Is a directory
这告诉我们两件事。 首先,我们无法抓住这样一个事实,即我们在 fin
的构造函数之后将目录作为文件打开。 其次,仅在使用迭代器时引发异常。 上面noIterators
的代码在从目录中读取时不会引发异常。 相反,它设置了坏位。 为什么代码会在一种情况下抛出异常并在另一种情况下设置坏位?
编辑 2
我从上面扩展了目录打开代码,以便更好地跟踪正在发生的事情
#include <iostream>
#include <vector>
#include <iterator>
#include <fstream>
#include <string>
void withIterators() {
std::ifstream fin("mydirectory");
if(!fin.is_open())
perror("Error opening file");
std::istreambuf_iterator <char> eos;
std::istreambuf_iterator <char> fin_it(fin.rdbuf());
std::string str;
try {
std::copy(fin_it,eos,std::back_inserter(str));
} catch(...) {
perror("Error reading file");
}
}
void withIteratorsUnderflow() {
std::ifstream fin("mydirectory");
try {
fin.rdbuf()->sgetc();
} catch(...) {
perror("Error reading file");
}
}
void withOtherIterators() {
std::ifstream fin("mydirectory");
if(!fin.is_open())
perror("Error opening file");
std::istream_iterator <char> eos;
try {
std::istream_iterator <char> fin_it(fin);
} catch(...) {
perror("Error making iterator");
}
}
void noIterators() {
std::ifstream fin("mydirectory");
if(!fin.is_open())
perror("Error opening file");
std::string line;
while(getline(fin,line)) {}
if(fin.bad())
perror("Error reading file");
}
int main() {
withIterators();
withIteratorsUnderflow();
withOtherIterators();
noIterators();
}
基本上,我们在不同的地方得到例外,或者没有,但出于类似的原因。
在withIterators()
,对copy
的调用最终调用代码/usr/lib/gcc/i686-pc-linux-gnu/4.7.3/include/g++-v4/bits/streambuf_iterator.h:187
,它声明
else if (!traits_type::eq_int_type((__ret = _M_sbuf->sgetc())
对sgetc()
的调用会引发异常。 很可能,这是按照@user657267的建议调用下溢。
在withIteratorsUnderflow()
,我们看到异常被sgetc
直接抛出,这证实了withIterators()
会发生什么。
在withOtherIterators()
,我们在创建std::istream_iterator
后立即抛出异常。 这与 std::istreambuf_iterator
发生的情况不同,后者直到后来才抛出异常。 无论如何,在构造过程中,我们将代码称为 /usr/lib/gcc/i686-pc-linux-gnu/4.7.3/include/g++-v4/bits/stream_iterator.h:121
,它声明
*_M_stream >> _M_value;
基本上,类istream_iterator
创建一个构造istream
,该立即尝试读取字符,从而引发异常。
在 noIterators()
上,getline
只是设置坏位,不会抛出异常。
底线是尝试从目录中读取是不好的。 有没有一个好的stl(不是boost(方法来检测这一点? 是否有其他情况会引发需要捕获的特定于实现的异常?
istreambuf_iterator
本身永远不会抛出。
它迭代basic_filebuf
会像调用std::fopen
一样打开文件(无论它是否真的这样做都无关紧要(。
正如你在这个问题中看到的,标准 C 没有目录的概念,所以尝试打开一个目录要么是实现定义的行为,要么是未定义的行为。在 gcc 的情况下(或者更确切地说是 libc(,目录可以打开,但你不能用它做太多事情。
根据标准,basic_filebuf
也永远不会抛出,但由于您已经通过尝试打开不是文件的内容超出了标准强制执行的范围,因此当您尝试从目录中读取时,libstdc++ 可以自由抛出异常。
检查给定名称是否为文件通常取决于平台,但boost::filesystem
/std::experimental::filesystem
提供便携式检查。
要回答您的编辑,尝试从流中读取时不会看到异常,因为哨兵将失败,并且流永远不会从缓冲区读取(最终调用underflow
(。 istreambuf_iterator
直接在缓冲区上运行,因此没有哨兵。
事实证明,libstdc++不会对overflow
进行类似的调用,并且由于underflow
的设置方式,如果流打开进行写入并且overflow
返回eof,则不会抛出异常。
- 处理多个异常集合的C++方法
- 我在c++代码中生成了一个运行时#3异常
- 何时在引用或唯一指针上使用移动语义
- 孤立代码块在结构中引发异常
- C++中的赋值发生,尽管右侧出现异常
- 何时提供默认参数作为模板参数
- 在将变量声明为引用时,堆在释放后使用
- 从构造函数抛出异常时如何克服内存泄漏
- 异常属于C++中的线程还是进程
- 当类定义不可见时捕获异常
- C++-明确何时以及如何调用析构函数
- 引发异常:读取访问冲突**dynamicArray**为0x1118235.发生
- 为什么异常不退出程序?
- 为什么我应该在异常处理中使用std::cerr而不是std::cout
- c++ 中的异常类何时初始化?
- Dynamic_cast何时返回0,什么时候引发异常?CPP
- istreambuf_iterator何时引发异常
- C++何时处理异常
- C++何时使用哪个(标准)异常
- 确切地说,何时捕捉到异常