Mon*_*ldo 14 c++ pointers iostream ostream
我正在玩弄溪流一点点,无法理解下面的内容.
这里我们有一个基本的ostream ptr,设置为不同的输出流,无论是cout
,cerr
还是a file
.
// ostream ptr
std::ostream* outstream;
// set output ostream
void setOutput(std::ostream & os)
{
outstream = &os;
}
// write message to ostream
void writeData(const std::string & msg)
{
*outstream << msg << '\n';
}
int main (int argc, char * const argv[])
{
// init to std out
setOutput(std::cout);
writeData("message to cout");
setOutput(std::cerr);
writeData("message to cerr");
std::ofstream fileout("test.txt", std::ofstream::out | std::ofstream::app);
setOutput(fileout);
writeData("message to file");
//fileout.close();
setOutput(std::cout);
writeData("message2 to cout");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以上工作完美,并显示了c ++ iostream实现的强度.完善.
但是,由于setOutput
通过引用设置,引用的对象必须保持在范围内.这就是问题出现的地方.std::cout
如果ofstream或任何其他ostream无效,我想找出一种默认输出的方法.也就是说,引用的对象是或超出范围.
例如:
// write message to ostream
void writeData(const std::string & msg)
{
if (/*stream or memory is invalid*/)
setOutput(std::cout);
*outstream << msg << '\n';
}
// local fileout goes out of scope
void foo()
{
std::ofstream fileout("test.txt", std::ofstream::out | std::ofstream::app);
setOutput(fileout);
writeData("message to file");
}
int main (int argc, char * const argv[])
{
setOutput(std::cout);
writeData("message to cout");
foo();
/* problem the local fileout is no longer referenced by the ostream ptr*/
/* the following should be redirected to std::cout cuz of default*/
writeData("message2 to cout");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
以上是好的,直到foo()
返回主函数.它出现了可怕的错误,因为本地定义的ofstream
不再可用.
显然这是不可取的,用户应该意识到这一点.但是我希望将所有这些包装在日志记录类中,从而保持对象的状态有效,即使这种滥用可能会发生.它会导致无效的访问冲突,很难找到.
具体问题.有没有办法弄清楚ostream ptr或任何ptr是否仍然引用有效的对象或内存位置?
ps:我可以使用堆内存并使用智能指针执行某些操作但坦率地说,如果可能的话,我想保留它
eer*_*ika 13
具体问题.有没有办法弄清楚ostream ptr或任何ptr是否仍然引用有效的对象或内存位置?
没有.没有办法用原始指针来解决这个问题.至少不是标准的c ++.
只要指向对象,您将需要保证指向的对象保持活动状态.
用于提供该保证的常见模式是RAII,如其他答案中所详述.保证指针有效性的另一种方法是使用智能指针而不是原始指针.但是,这些与自动变量不兼容.
只要你能保证指针没有被解除引用,就可以继续指向死对象.这通常很难保证,因为如前所述,没有办法测试指向的对象是否存在.
mer*_*011 10
这听起来像是RAII的一个很好的用例.
编写一个类,它将一个文件名和一个std::ostream**
as参数作为其构造函数.在所述类的构造函数中,构造ofstream(作为成员),并将指针设置为ofstream.在析构函数中,恢复为stdout
.
然后,使用新类的声明替换以下函数的前两行.
void foo()
{
std::ofstream fileout("test.txt", std::ofstream::out | std::ofstream::app);
setOutput(fileout);
writeData("message to file");
}
Run Code Online (Sandbox Code Playgroud)
您应该使用RAII强制正确设置流,然后如果对象被销毁则设置回std :: cout.
class OutputStream
{
protected:
static std::ostream*& internalGlobalStateOfOutputStream()
{
static std::ostream* out = &std::cout;
return out;
}
public:
static std::ostream& getOutputStream()
{
return *internalGlobalStateOfOutputStream();
}
};
template<typename T>
class OutputStreamOwner: public OutputStream
{
T ownedStream;
public:
OutputStreamOwner(T&& obj)
: ownedStream(std::move(obj))
{
internalGlobalStateOfOutputStream() = &ownedStream;
}
template<typename... Args>
OutputStreamOwner(Args... args)
: ownedStream(args...)
{
internalGlobalStateOfOutputStream() = &ownedStream;
}
~OutputStreamOwner()
{
internalGlobalStateOfOutputStream() = & std::cout;
}
// Delete copy
OutputStreamOwner(OutputStreamOwner const&) = delete;
OutputStreamOwner& operator(OutputStreamOwner const&) = delete;
};
Run Code Online (Sandbox Code Playgroud)
用法是:
void foo()
{
OutputStreamOwner<std::ofstream> output("test.txt", std::ofstream::out | std::ofstream::app);
writeData("message to file");
}
Run Code Online (Sandbox Code Playgroud)