如何在该引用超出范围后检测ptr是否仍引用有效引用

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,如其他答案中所详述.保证指针有效性的另一种方法是使用智能指针而不是原始指针.但是,这些与自动变量不兼容.

只要你能保证指针没有被解除引用,就可以继续指向死对象.这通常很难保证,因为如前所述,没有办法测试指向的对象是否存在.

  • 他们被称为"原始指针",因为他们是古代C程序员早餐吃的东西. (4认同)
  • @nicomp为了扩展user2078303的评论,能够做OP之类的事情的愿望是如此之大,以至于我们发明了各种各样的"指针"(指向的类),它们提供了关于生命周期的保证.宾语.这些已经变得非常受欢迎,以至于人们开始称指针为"原始指针",要特别注意指出它们带来的保证很少,并且温和地鼓励人们使用更智能的指针.我也听说过它们被称为"原生指针",但"原始"更常见. (3认同)
  • @nicomp'原始'指针是正确的指针.我使用'raw'限定符来区分智能指针,即使它们不是正确的指针也可以被认为是从抽象的角度来看的指针.我需要区分,因为在一些智能指针的情况下,你*可以*弄清楚指向的对象是否仍然有效,而在其他情况下,智能指针本身负责在不再引用对象时销毁对象所以没有必要弄清楚. (2认同)

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)


Mar*_*ork 5

您应该使用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)