Ich bin meine eigene streambuffer für Ausgabestream implementieren. Im Grunde ist es ein vektorartiger Strompuffer, in dem die Überlauffunktion den Puffer einfach zweimal zuweist. Die Synchronisierungsfunktion schreibt alle Daten auf das Gerät, das durch einen Dateideskriptor fd
festgelegt wurde.Anpassen streambuffer für C++ ostream
class MyStreamBuf : public ::std::streambuf {
constexpr static size_t INIT_BUFFER_SIZE {1024};
public:
MyStreamBuf();
~MyStreamBuf();
void fd(const int);
int sync() override;
int_type overflow(int_type ch = traits_type::eof()) override;
private:
int _fd {-1};
size_t _size;
char_type* _base;
void _resize(const size_t);
};
MyStreamBuf::MyStreamBuf() {
_size = INIT_BUFFER_SIZE;
_base = static_cast<char_type*>(malloc(_size * sizeof(char_type)));
setp(_base, _base + _size - 1); // -1 to make overflow easier.
}
// Destructor.
MyStreamBuf::~MyStreamBuf() {
::free(_base);
}
// Procedure: fd
// Change the underlying device.
void MyStreamBuf::fd(const int fd) {
_fd = fd;
}
// Procedure: _resize
// Resize the underlying buffer to fit at least "tgt_size" items of type char_type.
void MyStreamBuf::_resize(const size_t tgt_size) {
// Nothing has to be done if the capacity can accommodate the file descriptor.
if(_size >= tgt_size) return;
// Adjust the cap to the next highest power of 2 larger than num_fds
for(_size = (_size ? _size : 1); _size < tgt_size; _size *= 2);
// Adjust and reset the memory chunk.
_base = static_cast<char_type*>(::realloc(_base, _size*sizeof(char_type)));
setp(_base, _base + _size - 1); // -1 to make overflow easier.
}
int MyStreamBuf::sync() {
int res = 0;
::std::ptrdiff_t remain = pptr() - pbase();
while(remain) {
issue_write:
auto ret = ::write(_fd, pptr() - remain, remain);
if(ret == -1) {
if(errno == EINTR) {
goto issue_write;
}
else if(errno == EAGAIN) {
break;
}
else {
res = -1;
break;
}
}
remain -= ret;
}
if(remain) {
::memcpy(pbase(), pptr() - remain, remain*sizeof(char_type));
}
pbump(pbase() + remain - pptr());
return res;
}
typename MyStreamBuf::int_type MyStreamBuf::overflow(int_type ch) {
assert(traits_type::eq_int_type(ch, traits_type::eof()) == false);
_resize(_size * 2);
return ch;
}
aber ich bin immer segfault während der cout
mit meinem eigenen Puffer zu ersetzen. Ich konnte nicht finden, wo der Fehler ist, nachdem ich mit GDB gekämpft habe.
// Function: main
int main() {
auto fd = open("./test.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
MyStreamBuf d;
d.fd(fd);
::std::cout.rdbuf(&d);
::std::cout << 1 << " " << 2 << ::std::endl;
close(fd);
return 0;
}
Ist etwas falsch mit dieser Implementierung? Ich sah viele Artikel, die in der Regel Vorrang haben sync
und overflow
sind erforderlich.