C ++,std :: ofstream,异常

时间:2011-08-05 16:28:36

标签: c++ exception ofstream

此代码有什么问题以及如何解决?

int _tmain(int argc, _TCHAR* argv[])
{
std::ostream * o = &std::cout;
char text[4096];
char *file = "D://test.txt";

if ( file != NULL ) 
{
  strcpy ( text, file );
  strcat ( text, ".log" );
  o = & std::ofstream ( text );
}
*o << "test"; //Exception
return 0;
}

6 个答案:

答案 0 :(得分:4)

o = & std::ofstream ( text );

右侧表达式创建一个临时表达式,您将获得在表达式结尾处销毁的临时表的地址。之后使用o将调用未定义的行为。

你应该这样做:

{
   //...
   o = new std::ofstream ( text );
   if ( *o )
        throw std::exception("couldn't open the file");
}
//...

if  ( o != &std::cout )
   delete o; //must do this!

答案 1 :(得分:2)

它不应该编译;表达式std::ofstream( text )是一个 rvalue(临时),C ++不允许你获取地址 (临时的操作员&)。而临时的生命只是 直到完整表达式结束,所以它的析构函数将被调用 (以及它所驻留的内存可能会用于其他事情) 你在声明的最后传递了;

只是让ofstream成为一个命名的局部变量也无济于事, 因为变量的生命周期只到块的末尾 声明了它(下一个})。你必须定义 在std::ofstream之前if,打开它并在if中设置o, e.g:

std::ofstream mayOrMayNotBeUsed;
if ( file != NULL ) {
    //  ...
    mayOrMayNotBeUsed.open( text );
    if ( !mayOrMayNotBeUsed.is_open() ) {
        //  Do something intelligent here...
    }
    o = &mayOrMayNotBeUsed;
}

答案 2 :(得分:1)

问题是此代码导致未定义的行为:

o = & std::ofstream ( text );

写作时

std::ofstream ( text )

这将创建一个临时ostream对象,其生命周期在其完成执行后立即结束。当您获取其地址并将其分配给指针o时,指针现在指向其生命周期即将结束的临时对象。一旦语句完成执行,o现在指向其生命周期已结束的对象,因此使用该对象具有未定义的行为。因此,当你写

*o << "test";

您正在尝试对死对象执行操作,从而导致问题。

要解决此问题,您应该

  1. 通过编写ofstream动态分配o = new std::ofstream(text);,这会创建对象,使其生命周期延伸到语句末尾,或
  2. std::ofstream的顶部声明_tmain,以便其生命周期延伸到整个函数的其余部分。
  3. 希望这有帮助!

答案 3 :(得分:1)

o = & std::ofstream ( text );这会创建一个临时的ofstream对象,其地址被分配给o,但对象会立即被销毁,因此o指向已删除的对象。这应该有效(使用静态):

int _tmain(int argc, _TCHAR* argv[])
{
    std::ostream * o = &std::cout;
    char text[4096];
    char *file = "D://test.txt";

    if ( file != NULL ) 
    {
        strcpy ( text, file );
        strcat ( text, ".log" );
        static std::ofstream myofstream( text );
        o = &myofstream;
    }
    *o << "test"; //Exception
    return 0;
}

答案 4 :(得分:1)

o = & std::ofstream ( text );

创建临时对象,o开始指向此对象的地址,稍后(在执行此行之后),对象将被销毁。因此未定义的行为(当取消引用无效指针时)。

解决方案 - 使用new

创建它
o = new std::ofstraem( text );

但在return

之前,不要忘记释放已分配的内存
*o << "test";

if  ( &std::cout != o  ) // don't forget the check .. as I did at the first time
{
    o->close();  // not absolutely necessary, 
             // as the desctructor will close the file
    delete o;
}
return 0;

答案 5 :(得分:0)

我担心你会以非常不健康的方式混合使用C和C ++。

首先,我衷心建议使用std::string代替char*,相信我,你的麻烦会少得多。

其次,你应该注意指针:如果你不小心的话,他们可能会指出内存中不再存在任何“实时”对象的位置。

我建议使用以下代码:

void execute(std::ostream& out) {
  out << "test\n";
} // execute

int main(int argc, char* argv[]) {
  if (argc == 1) {
    execute(std::cout);
    return 0;
  }

  std::string filename = argv[1];
  filename += ".log";

  std::ofstream file(filename.c_str());
  execute(file);
  return 0;
}

其中说明了如何避免陷入的两个陷阱:

  • 使用std::string我避免分配静态大小的缓冲区,因此我冒着缓冲区溢出的风险。此外,操作也更容易。
  • 使用一个函数来提升打印逻辑,我不再使用指针及其引入的细微问题。

令人遗憾的是,std::stringstd::fstream(和配偶)目前并没有这么好。历史缺陷...如果我没记错的话,用C ++ 0x修复。