此代码有什么问题以及如何解决?
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;
}
答案 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";
您正在尝试对死对象执行操作,从而导致问题。
要解决此问题,您应该
ofstream
动态分配o = new std::ofstream(text);
,这会创建对象,使其生命周期延伸到语句末尾,或std::ofstream
的顶部声明_tmain
,以便其生命周期延伸到整个函数的其余部分。希望这有帮助!
答案 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::string
和std::fstream
(和配偶)目前并没有这么好。历史缺陷...如果我没记错的话,用C ++ 0x修复。