С одной стороны, вы не можете перепривязать ссылки после их создания, вы можете только инициализировать их. Вы можете подумать, что можете сделать это:
Log(std::string filename) : os(std::ofstream(filename)) {
if (!os.is_open())
// do errorry things
}
Но это нехорошо, потому что вы заставляете os
ссылаться на временную переменную.
Когда вам нужна ссылка, которая должна быть необязательной , то есть она должна ссылаться на что-то иногда, а не в другое время, вам действительно нужен указатель :
class Log {
private:
std::ostream* os;
bool dynamic;
public:
Log(std::ostream& os = std::cout): os(&os), dynamic(false) { }
Log(std::string filename) : dynamic(true) {
std::ofstream* ofs = new std::ofstream(filename);
if (!ofs->is_open())
// do errorry things and deallocate ofs if necessary
os = ofs;
}
~Log() { if (dynamic) delete os; }
};
Приведенный выше пример просто показывает вам, что происходит, но вы, вероятно, захотите управлять им с помощью умного указателя. Как указывает Бен Фойгт, есть много ошибок, которые могут вызвать непредвиденное и нежелательное поведение в вашей программе; например, когда вы попытаетесь сделать копию вышеупомянутого класса, он поразит поклонника. Вот пример вышесказанного с использованием умных указателей:
class Log {
private:
std::unique_ptr<std::ostream, std::function<void(std::ostream*)>> os;
public:
Log(std::ostream& os = std::cout): os(&os, [](ostream*){}) { }
Log(std::string filename) : os(new std::ofstream(filename), std::default_delete<std::ostream>()) {
if (!dynamic_cast<std::ofstream&>(*os).is_open())
// do errorry things and don't have to deallocate os
}
};
Необычный os(&os, [](ostream*){})
делает указатель указателем на данный ostream&
, но ничего не делает, когда он выходит из области видимости; это дает ему функцию удаления, которая ничего не делает. Вы можете сделать это и без лямбд, в этом примере это проще.