【问题标题】:Several ifstreams access-violation多个 ifstream 访问冲突
【发布时间】:2011-12-30 21:45:55
【问题描述】:

我尝试实现外部合并排序 (wiki),我想打开 2048 个 ifstream 并将数据读取到个人缓冲区。

ifstream *file;
file = (ifstream *)malloc(2048 * sizeof(ifstream));

for (short i = 0; i < 2048; i++) {
    itoa(i, fileName + 5, 10);
    file[i].open(fileName, ios::in | ios::binary); // Access violation Error
    if (!file[i]) {
        cout << i << ".Bad open file" << endl;          
    }
    if (!file[i].read((char*)perfile[i], 128*4)) {
        cout << i << ". Bad read source file" << endl;
    }       
}

但是,它会因

而崩溃

sorting.exe 中 0x58f3a5fd (msvcp100d.dll) 处未处理的异常:0xC0000005:访问冲突读取位置 0xcdcdcdfd。

是否可以使用这么多打开的ifstreams? 或者说开2048个ifstreams是个很糟糕的主意,还有更好的方法来实现这个算法?

【问题讨论】:

  • 访问冲突发生时i 的值是多少?
  • 可能是因为你malloc而不是new,所以ifstreams的构造函数没有被调用,所以有问题。
  • @Shahbaz:i 的值将是 0 - 令人惊讶

标签: c++ heap-memory ifstream access-violation


【解决方案1】:

非 POD 对象的数组使用new 分配,而不是malloc,否则构造函数不会运行。

您的代码正在获取未初始化的内存并将其“解释”为ifstreams,这显然会导致崩溃(因为该类的构造函数尚未运行,甚至虚拟表指针都没有到位)。

您可以在堆栈上分配所有对象:

ifstream file[2048];

如果需要考虑堆栈占用,则将它们分配到堆上;

ifstream *file=new ifstream[2048];
// ...
delete[] file; // frees the array

(虽然你应该在这里使用智能指针来避免异常情况下的内存泄漏)

或者,更好的是,使用ifstream 中的vector(需要标头&lt;vector&gt;):

vector<ifstream> file(2048);

不需要显式释放其元素。

(理论上,您可以使用malloc,然后使用放置new,但我根本不推荐)


...此外,同时打开 2048 个文件感觉不是一个好主意...

【讨论】:

  • @Shahbaz:一点点(有道理的)咆哮就足以扼杀一个完整的(我希望是正确的)答案?
  • 好吧,没有理由特意去攻击一个明显的初学者。
  • 完成。我希望你现在会更喜欢它。
  • 我删除了我的 -1。如果你是来帮忙的,试着做一个善良的老师,而不是一个愤怒的大四学生。
【解决方案2】:

这是 C++。ifstream 是非 POD,所以你不能只是 malloc 它:实例需要得到构造

ifstream file[2048];

for (short i = 0; i < 2048; i++) {
    itoa(i, fileName + 5, 10);
    file[i].open(fileName, ios::in | ios::binary); // Access violation Error
    if (!file[i]) {
        cout << i << ".Bad open file" << endl;          
    }
    if (!file[i].read((char*)perfile[i], 128*4)) {
        cout << i << ". Bad read source file" << endl;
    }       
}

除此之外,打开 2048 个文件听起来不是一个好计划,但你可以稍后再考虑

【讨论】:

    【解决方案3】:

    0xcdcdcdcd被VS在调试模式下用来表示未初始化的内存(还要留意0xbaadf00d)。

    您正在使用 malloc,它是 C 遗产,并且 调用构造函数,它只是为您提供了一个指向数据块的指针。 ifstream 不是 POD(普通旧数据)类型;它需要您调用其构造函数才能正确初始化。这是 C++;使用newdelete

    更好的是,两者都不要使用;只需在堆栈上构造事物并让它处理应使用的动态内存分配。

    当然,这甚至没有涉及打开 2048 个文件的可怕想法,但您可能应该以艰难的方式学习这一点...

    【讨论】:

    • 谢谢。似乎操作系统不允许打开这么多文件——我使用了新的,但是在 i == 508 上发生了打开文件错误。那么......有什么更好的方法呢?只需打开、阅读和关闭?
    • @Shahbaz:IIRC 0xcdcdcdcd 由 VC++ 调试堆使用,而 0xbaadf00d 由 Windows 调试堆使用(只要进程启动并附加调试器就会激活)。
    • @user1050686:文件句柄是有限的资源。完成后,您应该关闭每个文件。您不需要数组;你需要一个作用域ifstream。离开范围时它将关闭,即在 for 循环中声明变量(已分配堆栈!)。查找 RAII 和 read this
    【解决方案4】:

    您无法打开 2048 个文件,打开文件有操作系统限制

    【讨论】:

    • 这可能是真的,但绝对不是问题
    • @sehe:你说得对,它是关于非构造对象的。我会保留这可能是另一个问题
    【解决方案5】:

    据我所知,这里根本不需要 2048 个单独的 ifstreams 数组。在任何给定时间您只需要 一个 ifstream,因此每次迭代您都会关闭一个文件并打开另一个文件。销毁 ifstream 会自动关闭文件,因此您可以执行以下操作:

    for (short i = 0; i < 2048; i++) {
        itoa(i, fileName + 5, 10);
        ifstream file(fileName, ios::in | ios::binary);
        if (!file) {
            cout << i << ".Bad open file" << endl;          
        }
        if (!file.read((char*)perfile[i], 128*4)) {
            cout << i << ". Bad read source file" << endl;
        }       
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-06
      • 2013-02-26
      • 2015-04-23
      • 2018-04-16
      • 1970-01-01
      相关资源
      最近更新 更多