Что может пойти не так, если cout.rdbuf () используется для переключения буфера и никогда не устанавливает его обратно?

Автор представил этот код под заголовком A bus error on my platform

#include <fstream>
#include <iostream>

int main()
{
std::ofstream log("oops.log");
std::cout.rdbuf(log.rdbuf());
std::cout << "Oops!\n";
return 0;
}

Строка «Oops! \ N» выводится в файл «oops.log». Код не восстанавливает streambuf cout, но VS2010 не сообщил об ошибке во время выполнения.

6

Решение

поскольку log а также std::cout поделиться буфером, этот буфер, вероятно, будет освобожден дважды (один раз, когда log выходит из области видимости, затем еще раз, когда программа завершается).

Это приводит к неопределенному поведению, поэтому трудно сказать точную причину, по которой это вызывает ошибку шины на его компьютере, но на вашем компьютере ничего не происходит.

9

Другие решения

Поскольку в других ответах не упоминается, что с этим делать, я приведу это здесь. Вам нужно сохранить и восстановить буфер, которым должен управлять cout. Например:

#include <fstream>
#include <iostream>

// RAII method of restoring a buffer
struct buffer_restorer {
std::ios &m_s;
std::streambuf *m_buf;

buffer_restorer(std::ios &s, std::streambuf *buf) : m_s(s), m_buf(buf) {}
~buffer_restorer() { m_s.rdbuf(m_buf); }
};

int main()
{
std::ofstream log("oops.log");
buffer_restorer r(std::cout, std::cout.rdbuf(log.rdbuf()));
std::cout << "Oops!\n";
return 0;
}

Теперь когда coutбуфер заменяется раньше cout уничтожается в конце программы, поэтому, когда cout уничтожает свой буфер, происходит правильная вещь.


Для простого перенаправления стандартного ввода-вывода обычно в среде уже есть возможность сделать это за вас (например, перенаправление ввода-вывода в оболочке). Вместо приведенного выше кода я бы, вероятно, просто запустил программу как:

yourprogram > oops.log

Также следует помнить, что std::cout является глобальной переменной со всеми теми же недостатками, что и другие глобальные переменные. Вместо того, чтобы изменять его или даже использовать его, вы можете предпочесть использовать обычные методы, чтобы избежать глобальных переменных все вместе. Например, вы можете передать std::ostream &log_output параметр вокруг и использовать его вместо использования кода cout непосредственно.

4

Ваша программа имеет неопределенное поведение.

Деструктор глобального cout объект удалит буфер потока при выходе из области видимости, и то же самое верно для log, который также владеет тем же буфером потока. Таким образом, вы удаляете один и тот же объект дважды.

Когда программа имеет неопределенное поведение, может произойти все что угодно, от форматирования жесткого диска до завершения без каких-либо ошибок.

На моей платформе, например, программа входит в бесконечный цикл после возвращения из main(),

3
По вопросам рекламы [email protected]