C++,std::ofstream,异常

发布于 2024-11-28 03:54:07 字数 328 浏览 2 评论 0原文

这段代码有什么问题以及如何修复它?

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

再浓的妆也掩不了殇 2024-12-05 03:54:08

它不应该编译;表达式 std::ofstream( text ) 是一个
右值(临时的),并且 C++ 不允许您获取该地址
(运算符&)临时的。而临时的生命周期只是
直到完整表达式结束,所以它的析构函数将被调用
(并且它驻留的内存可以用于其他事情)一旦
您在语句末尾传递 ;

仅将 ofstream 设为命名局部变量也无济于事,
因为变量的生命周期仅到块的末尾
它被声明(下一个 })。你必须定义
if之前的std::ofstream,打开它并在if中设置o
例如:

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

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. 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 }). You have to define the
std::ofstream before the if, and open it and set o in the if,
e.g.:

std::ofstream mayOrMayNotBeUsed;
if ( file != NULL ) {
    //  ...
    mayOrMayNotBeUsed.open( text );
    if ( !mayOrMayNotBeUsed.is_open() ) {
        //  Do something intelligent here...
    }
    o = &mayOrMayNotBeUsed;
}
美人骨 2024-12-05 03:54:08

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

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. 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;
}
甚是思念 2024-12-05 03:54:08

问题是这段代码会导致未定义的行为:

o = & std::ofstream ( text );

当您编写

std::ofstream ( text )

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

*o << "test";

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

要解决此问题,您应该

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

希望这有帮助!

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. 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. 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. 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);, 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.

Hope this helps!

月亮是我掰弯的 2024-12-05 03:54:08

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;

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. Thus undefined behavior (when dereferencing invalid pointer).

The solution - create it with new:

o = new std::ofstraem( text );

BUT don't forget to free the allocated memory, before 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;
情归归情 2024-12-05 03:54:08

我担心您正在以一种非常不健康的方式混合 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 中修复。

You are mixing C and C++ in a very unhealthy way, I fear.

First, I heartily recommend using std::string instead of a char*, believe me, you'll have far less troubles.

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. 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. Historical defect... fixed in C++0x if I remember correctly.

强辩 2024-12-05 03:54:07
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!
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.

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!
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文