简体   繁体   English

C ++,std :: ofstream,异常

[英]C++, std::ofstream, exception

What is wrong in this code and how to fix it? 该代码有什么问题以及如何解决?

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;
}
o = & std::ofstream ( text );

The right-side expression creates a temporary and you get the address of the temporary which is destroyed at the end of the expression. 右侧表达式创建一个临时地址,您将获得该临时地址,该地址在表达式末尾被破坏。 After that using o would invoked undefined behaviour. 之后,使用o将调用未定义的行为。

You should be doing this: 您应该这样做:

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

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

It shouldn't compile; 它不应该编译; the expression std::ofstream( text ) is an rvalue (a temporary), and C++ doesn't allow you to take the address (operator & ) of a temporary. 表达式std::ofstream( text )是一个右值(临时值),C ++不允许您使用临时地址(运算符& )。 And the lifetime of a temporary is only until the end of the full expression, so its destructor will be called (and the memory it resides in may be used for other things) as soon as you pass the ; 临时项的生存期直到完整表达式的结尾,因此,一旦您通过,它的析构函数将被调用(并且其所驻留的内存可能会用于其他用途) ; at the end of the statement. 在声明的末尾。

Just making the ofstream a named local variable doesn't help, either, since the lifetime of a variable is only to the end of the block in which it was declared (the next } ). 仅将ofstream命名为局部变量也无济于事,因为变量的生存期仅是声明该变量的块的末尾(下一个} )。 You have to define the std::ofstream before the if , and open it and set o in the if, eg: 您必须在if之前定义std::ofstream然后将其打开并在if中设置o ,例如:

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

The problem is that this code results in undefined behavior: 问题在于此代码导致未定义的行为:

o = & std::ofstream ( text );

When you write 当你写

std::ofstream ( text )

This creates a temporary ostream object whose lifetime ends as soon as the statement it's in finishes executing. 这将创建一个临时的ostream对象,该对象的生存期将在其所包含的语句完成执行后立即结束。 When you take its address and assign it to the pointer o , the pointer now points at a temporary object whose lifetime is about to end. 现在,当您获取其地址并将其分配给指针o ,该指针现在指向一个寿命即将结束的临时对象。 As soon as the statement finishes executing, o is now pointing at an object whose lifetime has ended, so using that object has undefined behavior. 语句完成执行后, o现在指向其生存期已结束的对象,因此使用该对象具有未定义的行为。 Consequently, when you write 因此,当你写

*o << "test";

You're trying to perform an operation on a dead object, causing problems. 您试图对不活动的对象执行操作,从而导致问题。

To fix this, you should either 要解决此问题,您应该

  1. Dynamically-allocate the ofstream by writing o = new std::ofstream(text); 通过写o = new std::ofstream(text);动态分配ofstream , which creates the object such that its lifetime extends past the end of the statement, or ,它将创建对象,使其寿命超过语句的结尾,或者
  2. Declare the std::ofstream at the top of _tmain so that its lifetime extends throughout the rest of the function. _tmain的顶部声明std::ofstream ,以便其生存期遍及该函数的其余部分。

Hope this helps! 希望这可以帮助!

o = & std::ofstream ( text ); this creates a temporary ofstream object whose address is assigned to o but the object is instantly destroyed, so o points to a deleted object. 这将创建一个临时的ofstream对象,其地址分配给o但该对象立即被销毁,因此o指向已删除的对象。 This should work (using static): 这应该工作(使用静态):

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;
}

This 这个

o = & std::ofstream ( text );

creates temp object, o starts pointing to the address of this object and later(right after the execution of this row) the object is destroied. 创建临时对象, o开始指向该对象的地址,然后(在执行该行之后)销毁该对象。 Thus undefined behavior (when dereferencing invalid pointer). 因此, 行为不确定 (在取消引用无效指针时)。

The solution - create it with new : 解决方案-使用new创建它:

o = new std::ofstraem( text );

BUT don't forget to free the allocated memory, before return : 但是不要忘记在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;

You are mixing C and C++ in a very unhealthy way, I fear. 我担心,您正在以非常不健康的方式混合使用C和C ++。

First, I heartily recommend using std::string instead of a char* , believe me, you'll have far less troubles. 首先,我衷心推荐使用std::string代替char* ,相信我,您的麻烦会少很多。

Second, you should beware of pointers: they may point, if you are not careful, to places in memory that no longer host any "live" object. 其次,您应该提防指针:如果您不小心,它们可能指向内存中不再托管任何“活动”对象的位置。

I would propose the following code: 我会提出以下代码:

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;
}

Which illustrate how to avoid the two pitfalls you fell into: 这说明了如何避免陷入两个陷阱:

  • using std::string I avoid allocating a statically sized buffer, and thus I do risk a buffer overflow. 使用std::string可以避免分配静态大小的缓冲区,因此我确实有缓冲区溢出的风险。 Furthermore operations are so much easier. 此外,操作非常容易。
  • using a function to hoist out the printing logic, I do away with the pointer and the subtle issues it introduced. 使用函数提升打印逻辑,我消除了指针及其引入的细微问题。

It is unfortunate that std::string and std::fstream (and consorts) do not mix so well, at the moment. 不幸的是,目前std::stringstd::fstream (和配偶)混合得还不够好。 Historical defect... fixed in C++0x if I remember correctly. 历史缺陷...如果我没记错的话,已在C ++ 0x中修复。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM