C++ 意外的运行时错误(分段错误)
我目前正在优化一个内存密集型应用程序,以占用更少的内存。在下面的代码中,我试图动态地分配文件流对象C++ 意外的运行时错误(分段错误),c++,new-operator,binaryfiles,dynamic-memory-allocation,delete-operator,C++,New Operator,Binaryfiles,Dynamic Memory Allocation,Delete Operator,我目前正在优化一个内存密集型应用程序,以占用更少的内存。在下面的代码中,我试图动态地分配文件流对象ifstream和ofstream,以便在不再需要文件流使用后完全释放它们。代码对于流的的分配/取消分配非常有效,但在运行时由于ifstream的内存内容取消分配时可能出现分段错误而崩溃。以下是原始代码的一个片段: #include <fstream> using namespace std; // Dummy class to emulate the issue at hand cl
ifstream
和ofstream
,以便在不再需要文件流使用后完全释放它们。代码对于流的的分配/取消分配非常有效,但在运行时由于ifstream
的内存内容取消分配时可能出现分段错误而崩溃。以下是原始代码的一个片段:
#include <fstream>
using namespace std;
// Dummy class to emulate the issue at hand
class dummy {
private:
int randINT;
static bool isSeeded;
public:
dummy() { randINT=rand(); }
int getVal() { return randINT; }
};
bool dummy::isSeeded=false;
int main(int argc, const char* argv[]) {
// Binary file I/O starts here
dummy * obj;
ofstream * outputFile;
ifstream * inputFile;
outputFile=new ofstream("bFile.bin",ios::binary);
if (!(*outputFile).fail()) {
obj=new dummy;
cout << "Value to be stored: " << (*obj).getVal() << "\n";
(*outputFile).write((char *) obj, sizeof(*obj)); // Save object to file
(*outputFile).close();
delete obj;
// don't assign NULL to obj; obj MUST retain the address of the previous object it pointed to
} else {
cout << "Error in opening bFile.bin for writing data.\n";
exit(1);
}
delete outputFile; // This line throws no errors!
inputFile=new ifstream("bFile.bin",ios::binary);
if (!(*inputFile).fail()) {
(*inputFile).read((char *) obj,sizeof(dummy)); // Read the object of type 'dummy' from the binary file and allocate the object at the address pointed by 'obj' i.e. the address of the previously de-allocated object of type 'dummy'
cout << "Stored Value: " << (*obj).getVal() << "\n";
(*inputFile).close();
} else {
cout << "Error in opening bFile.bin for reading data.\n";
exit(1);
}
delete inputFile; // Runtime error is thrown here for no reason!
cout << "\n-----END OF PROGRAM-----\n";
}
#包括
使用名称空间std;
//虚拟类来模拟手头的问题
类虚拟{
私人:
int-randINT;
需要静态布尔;
公众:
dummy(){randINT=rand();}
int getVal(){return randINT;}
};
bool dummy::isseed=false;
int main(int argc,const char*argv[]{
//二进制文件I/O从这里开始
虚拟对象*obj;
流*输出文件;
ifstream*输入文件;
outputFile=newofstream(“bFile.bin”,ios::binary);
如果(!(*outputFile).fail()){
obj=新假人;
cout最多读取count
个字符,并将它们放置在地址
。它不会像您似乎相信的那样在地址
创建任何对象。地址
必须指向至少count*sizeof(char\u type)的有效内存块
大小。通过传递delete
d对象的地址,您违反了该条件:您的代码已损坏,并且分段错误不是意外的
编辑
你所做的是,简短的UB。当你这样做时,没有任何保证,任何关于按哪个顺序发生的逻辑都是无效的。程序可以做任何事情,包括立即崩溃、运行一段时间然后崩溃,或者
在您的例子中,我怀疑std::basic_istream::read()
写入未受保护的内存会导致某些数据被覆盖,例如另一个对象的地址,这会导致分段错误。但这纯粹是推测,不值得研究
在您的情况下,不会创建任何对象。二进制文件只包含一些字节。read()
将它们复制到提供的地址,该地址不是为此目的保留的。要避免UB,只需添加
obj = new dummy;
在执行之前,请阅读以创建对象
如果您想重新使用上一个对象的内存,可以使用(请参见该链接的第9点和第10点)
char*buffer = nullptr; // pointer to potential memory buffer
if(writing) {
if(!buffer)
buffer = new char[sizeof(dummy)]; // reserve memory buffer
auto pobj = new(buffer) dummy(args); // create object in buffer
write(buffer,sizeof(dummy)); // write bytes of object
pobj->~pobj(); // destruct object, but don't free buffer
}
if(reading) {
if(!buffer)
buffer = new char[sizeof(dummy)]; // not required if writing earlier
read(buffer,sizeof(dummy)); // read bytes into object
auto pobj = reinterpret_case<dummy*>(buffer); // no guarantees here
use(pobj); // do something with the object read
pobj->~pobj(); // destruct object
}
delete[] buffer; // free reserved memory
char*buffer=nullptr;//指向潜在内存缓冲区的指针
如果(书面){
如果(!缓冲区)
buffer=新字符[sizeof(dummy)];//保留内存缓冲区
auto pobj=new(buffer)dummy(args);//在buffer中创建对象
写入(缓冲区,sizeof(虚拟));//写入对象的字节
pobj->~pobj();//销毁对象,但不要释放缓冲区
}
如果(阅读){
如果(!缓冲区)
buffer=new char[sizeof(dummy)];//如果之前写入,则不需要
read(buffer,sizeof(dummy));//将字节读入对象
auto pobj=reinterpret_case(buffer);//这里没有保证
使用(pobj);//对读取的对象执行一些操作
pobj->~pobj();//析构函数对象
}
删除[]缓冲区;//释放保留内存
请注意,如果读取未生成有效对象,则该对象的后续使用,即对其析构函数的调用,可能会崩溃
然而,所有这些微观优化无论如何都是毫无意义的(只有当您能够避免对新建和删除的调用时,才值得这么做)不要浪费你的时间。< /P>请你提供问题。A你来自java或C++背景吗?因为在C++中,你不必使用<代码>新< /Cord>创建对象实例。这会导致指针变少,指针也少了,因为错误使用指针是崩溃最常见的原因。tFile=流的新文件(“bFile.bin”,ios::binary)
是一个非常糟糕的主意…你是故意想打败吗?对我来说最突出的是使用obj
你删除它指向的内存,但保留那个地址并试图重用它…这就是我要从这里开始的地方。@Baum mit Augen我在p我仍然不明白。如果问题是“传递已删除对象的地址”,那么存储的值将不会显示,因为读取()时会出错已调用。当您从二进制文件读取对象时,该对象不是已经创建了吗?@hecate欢迎使用未定义的行为!!。您可以使用作用域来控制对象何时解除分配,请查找RAII。