Подтвердить что ты не робот

Перенаправление std:: cout

Мне нужен класс, который перенаправляет один поток на другой поток во время его жизни. После некоторого мастерства я придумал это:

#include <iostream>
#include <fstream>


class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mRedirect(inRedirect)
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::ostream & mRedirect;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    return 0;
}

Кажется, все нормально. Однако странно, что следующая строка повторяется как в конструкторе, так и в деструкторе:

mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));

Я думаю, что это правильно, но я хотел бы проверить с сообществом SO. Вы можете найти какие-либо ошибки или опасности в этом коде?

редактировать

Сделать не скопированным.

4b9b3361

Ответ 1

Причина, по которой эти строки одинаковы, - это то, что вы делаете, это замена буферов. (То есть, вы "перенаправляете", заменяя исходный буфер буфером перенаправления, восстановление - это своп.)

Хотя это может дать вам предполагаемый эффект по отношению к выходному потоку, это не правильно, потому что поток перенаправления теперь выводит куда-то еще. Переадресация означает использовать один поток и выводить его в другое место; Обратите внимание, что это не влияет на то, что "где-то еще".

Ваш класс не является перенаправлением; как есть, его действительно следует называть ScopedStreamSwap. Например, попробуйте это вместо:

#include <iostream>
#include <fstream>

class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mRedirect(inRedirect)
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mRedirect.rdbuf(mOriginal.rdbuf()));
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::ostream & mRedirect;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;

        // oops:
        filestream << "also to the file, right?...nope" << std::endl;
        filestream << "ah, why am i on the screen?!" << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    // in main, return 0 is implicit, if there is no return statement;
    // helpful to keep in mind in snippets and short things
}

Что вы хотите, так это:

#include <iostream>
#include <fstream>

class ScopedRedirect
{
public:
    ScopedRedirect(std::ostream & inOriginal, std::ostream & inRedirect) :
        mOriginal(inOriginal),
        mOldBuffer(inOriginal.rdbuf(inRedirect.rdbuf()))
    { }

    ~ScopedRedirect()
    {
        mOriginal.rdbuf(mOldBuffer);
    }    

private:
    ScopedRedirect(const ScopedRedirect&);
    ScopedRedirect& operator=(const ScopedRedirect&);

    std::ostream & mOriginal;
    std::streambuf * mOldBuffer;
};


int main()
{
    std::cout << "Before redirect." << std::endl;
    std::ofstream filestream("redirected.txt");
    {
        ScopedRedirect redirect(std::cout, filestream);
        std::cout << "During redirect." << std::endl;

        // yay:
        filestream << "also to the file, right?...yes" << std::endl;
        filestream << "i am not on the screen" << std::endl;
    }
    std::cout << "After redirect." << std::endl;

    return 0;
}