2

標準ライブラリの事前定義されたオブジェクトにマップされる3つのデフォルトI/Oストリームがあることはよく知られています。

  • 0:std::istream std::cin
  • 1:std::ostream std::cout
  • 2:std::ostream std::cerrおよびstd::ostream std::clog

ただし、(たとえば)bashスクリプト内から、追加のストリーム(3,4、...)を作成できます。

では、記述子3を使用して追加の出力ストリームを作成し、それをstd::ostream customオブジェクトにバインドできますか?もしそうなら、どのように?std::ofstream「3」という名前のファイルが作成されるため、このトリックは実行されません。これは、私が望んでいるものではありません。


編集:それはポータブルである必要はありません。POSIXで動作する場合はそれで十分です。

4

3 に答える 3

2

プログラムを移植可能にする必要がある場合は不可能です。C ++ 11標準は、それを行うための統一された方法を指定していません。

overflow()ただし、システム固有のAPIを使用して、仮想関数とxsputn()仮想関数をオーバーライドし、指定された記述子を使用して各文字または文字のシーケンスをストリームに書き込む独自の出力ストリームバッファーを定義できます。

これらの線に沿った何か:

class my_ostream_buf : public std::streambuf
{

public:

    my_ostream_buf(int fd) : _fd(fd) { }

protected:

    virtual int_type overflow (int_type c)
    {
        if (c != EOF)
        {
            char ch = c;
            if (write(_fd, &ch, 1) != 1)
            {
                return EOF;
            }
        }

        return c;
    }

    // This is not strictly necessary, but performance is better if you
    // write a sequence of characters all at once rather than writing
    // each individual character through a separate system call.
    virtual std::streamsize xsputn(const char* s, std::streamsize num)
    {
        return write(_fd, s, num);
    }

private:

    int _fd = 0;    

};

そして、これはあなたがそれをどのように使うかです:

using namespace std;

int main()
{
    int fd = ...; // Any file descriptor
    my_ostream_buf buf(fd);

    ostream os(&buf); // Take care of the lifetime of `buf` here, or create your
                      // own class that derives from ostream and encapsulates an
                      // object of type my_ostream_buf

    os << "Hello" << endl;
}
于 2013-02-06T16:39:06.493 に答える
1

標準ではこれに何も提供されていません。std::filebufIOStreamの適切な実装では、システムファイル記述子(そのタイプはシステムによって異なります)を取得し、そこからfilebufを作成する、の実装固有のコンストラクターがいくつか追加されている必要があります。そうでない場合は、独自のstreambufを作成する必要があります。これは、必要なものに応じて、多かれ少なかれ難しい場合があります。単純な一方向のストリーム(読み取りまたは書き込み、両方ではない)が必要な場合、シークのサポートも入力でのコード変換もありません。比較的単純です。read(ただし、またはなどのシステムレベルの要求に精通している必要がありますwrite。)すべてをサポートする場合filebufは、はるかに複雑になります。

編集:

例を追加しようと思っただけです。あなたが話しているのでbash、私はUnixだと思います:

class FdStreambuf : public std::streambuf
{
    int myFd;
    char buffer[1024];

    bool writeBuffer()
    {
        int len = pptr() - pbase();
        return len == 0 || write( myFd, pptr(), len ) == len;
    }

protected:
    int overflow( int ch )
    {
        int results = ch == traits::eof() ? 0 : ch;
        if ( pbase() != NULL ) {
            if ( ! writeBuffer() ) {
                results = traits::eof();
            }
        }
        setp( buffer, buffer + sizeof( buffer ) );
        sputc( ch );
        return ch;
    }

    int sync()
    {
        return writeBuffer() ? 0 : -1;
    }

public:
    FdStreambuf( int fd ) : myFd( fd ) {}
    int close()
    {
        sync();
        return ::close( myFd );
    }
};

class FdOStream : private FdStreambuf, public std::ostream
{
public:
    FdOStream( int fd )
        : FdStreambuf( fd )
        , std::ostream( this )
    {
    }
    void close()
    {
        if ( FdStreambuf::close() != 0 ) {
            setstate( std::ios_base::badbit );
        }
    }
};

(必要なのはそれだけだと思いますが、何かを忘れてしまった可能性があります。)

于 2013-02-06T16:44:14.510 に答える
1

私はアンディジェームズの答えを組み合わせました、そしてこれは私が得たものです(誰かがこれを必要とする場合に備えて)

Streams.h

#pragma once

#include <ostream>
#include <unistd.h>

namespace util {
  class StreamWrapperImpl : public std::ostream {
    private:
      typedef std::streambuf* OwnedBufPtr;
      OwnedBufPtr const buf;
    public:
      StreamWrapperImpl(OwnedBufPtr buf)
      : std::ostream(buf)
      , buf(buf)
      {}
      virtual ~StreamWrapperImpl() {
        delete buf;
      }
  };
  template <typename Buf>
  class StreamWrapper : public StreamWrapperImpl {
    public:
      StreamWrapper()
      : StreamWrapperImpl(new Buf())
      {}
      template <typename Arg>
      StreamWrapper(Arg arg) // this could use some perfect forwarding in C++11
      : StreamWrapperImpl(new Buf(arg))
      {}
  };

  class FdStreamBuf : public std::streambuf {
    private:
      int fd;
    protected:
      virtual int_type overflow(int_type c) {
        if (c != EOF) {
          char const ch = c;
          if (write(fd, &ch, 1) != 1)
            return EOF;
        }
        return c;
      }
      virtual std::streamsize xsputn(char const* s, std::streamsize num) {
        return write(fd, s, num);
      }
    public:
      FdStreamBuf(int fd)
      : fd(fd)
      {
      }
  };
}
于 2013-02-06T23:30:29.443 に答える