为什么在try块中初始化文件指针会导致管道破裂

Why does initializing a file pointer inside a try block cause a broken pipe?

本文关键字:管道 指针 文件 try 初始化 为什么      更新时间:2023-10-16

我有一个bash脚本,我正在从我的程序中读取结果。Ptr是一个简单的popen()包装器。

bool getResult(const char* path){
  Ptr f(path);
  char buf[1024];
  while (fgets(buf, sizeof(buf), f) == 0) {
    if(errno == EINTR)
      continue;
    log.error("Error (%d) : %s",errno,path);
    return false;
  }
  ...
  return true;
}

这工作得很好,但Ptr f(path)不是异常安全,所以我用:

Ptr f; // empty constructor, does nothing
char buf[1024];
try{
  Ptr f(path);
}catch(Exception& e){
  vlog.error("Could not open file at %s",path);
  return false;
}

当运行(并且文件存在)时,我得到以下错误:

/etc/my_script: line 165: echo: write error: Broken pipe

脚本的那一行就是:

echo $result

怎么回事?

当你在try块中调用Ptr f(path)时,你创建了一个名为f的全新变量,当你退出try块时,它将被销毁。

那么任何在try块之外使用f的代码都将使用您在开始时创建的未初始化的f。

你有两个选项,我可以看到:

添加一个Open方法或类似于Ptr的方法,并从try块中调用它,或者可能将所有文件读/写代码包装在try块中,这样您就可以避免返回false的需要,因为当抛出异常时所有代码都将被跳过。

选项1:

Ptr f;
try
{
    f.Open( file );
}
catch
....

选项2:

try
{
    Ptr f( file );
    f.read();
}
catch
.....

这可能是一个作用域问题,替换为:

bool getResult(const char* path) 
{
  try
  {
     Ptr f(path);
     char buf[1024];
     while (fgets(buf, sizeof(buf), f) == 0) 
     {
       if(errno == EINTR)
         continue;
       log.error("Error (%d) : %s",errno,path);
       return false;
     }
  ...
  } 
  catch(Exception& e) 
  {
    vlog.error("Could not open file at %s",path);
    return false;
  }
  return true;
}