boost::multi_array 上的分段错误

以下代码给出了分段错误:

The following code gives a segmentation fault:

#include <iostream>
#include <fstream>
#include "binItr.h"
#include <boost/multi_array.hpp>

using namespace std;

int main(){
   const char * xifile = "results/feretxiG1155V0P5T231K10.bin";

   const uint pSize = 5;
   const uint T = 231;

   ifstream xiFileId(xifile, ios::binary);

   typedef boost::multi_array<uint, 2> array_type;
   array_type xi(boost::extents[T][pSize + 1]);

   //the ii_t class in the following line is taken from http://stackoverflow.com/questions/1855704/c-binary-file-i-o-to-from-containers-other-than-char-using-stl-algorithms written by http://stackoverflow.com/users/14065/loki-astari

   ii_t<uint> xi_in(xiFileId);

   copy(xi_in, ii_t<uint>(), xi.data());
   return 0;
}

输入二进制文件包含 unsigned int 数据,ls -l 报告的大小为 231*(5+1)4 = 5544 字节.我尝试读取文件并将数据存储在向量中,发现向量大小为 231(5+1) = 1386.使用 gdb 分析核心文件得到以下输出.

The input binary file contains unsigned int data and its size as reported by ls -l is 231*(5+1)4 = 5544 bytes. I tried reading the file and storing the data in a vector and found that vector size is 231(5+1) = 1386. Analysis of the core file using gdb gives the following output.

    Program terminated with signal 6, Aborted.

    #0  0x00007fb71130ea75 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
64   ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
   in ../nptl/sysdeps/unix/sysv/linux/raise.c

    (gdb) bt
    #0  0x00007fb71130ea75 in raise (sig=<value optimized out>) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
    #1  0x00007fb7113125c0 in abort () at abort.c:92
    #2  0x00007fb7113484fb in __libc_message (do_abort=<value optimized out>, fmt=<value optimized out>) at ../sysdeps/unix/sysv/linux/libc_fatal.c:189
    #3  0x00007fb7113525b6 in malloc_printerr (action=3, str=0x7fb711425cd8 "double free or corruption (!prev)", ptr=<value optimized out>) at malloc.c:6266
    #4  0x00007fb711358e83 in __libc_free (mem=<value optimized out>) at malloc.c:3738
    #5  0x00000000004018c4 in __gnu_cxx::new_allocator<unsigned int>::deallocate (this=0x7fffc618d2f8, __p=0x2295290) at /usr/include/c++/4.4/ext/new_allocator.h:95
    #6  0x000000000040152f in boost::multi_array<unsigned int, 2ul, std::allocator<unsigned int> >::deallocate_space (this=0x7fffc618d290) at /usr/include/boost/multi_array.hpp:484
    #7  0x0000000000401077 in boost::multi_array<unsigned int, 2ul, std::allocator<unsigned int> >::~multi_array (this=0x7fffc618d290, __in_chrg=<value optimized out>) at /usr/include/boost/multi_array.hpp:468
    #8  0x0000000000400d4e in main () at segTest.cpp:30

有什么建议吗?谢谢.

推荐答案

问题是 ii_t<> 输入迭代器类/questions/1855704/c-binary-file-io-to-from-containers-other-than-char-using-stl-algorithms/1856092#1856092">refered SO answer 是阅读"太多项目,因为包装的 istream 不返回 EOF 直到迭代器的取消引用 after 返回文件中的最后一项.额外返回的数据项正在破坏 multi_array 对象中分配的内存块.

The problem is that the ii_t<> input iterator class from the referred SO answer is 'reading' one too many items because the wrapped istream doesn't return EOF until the the dereference of the iterator after the one that returned the last item in the file. The extra returned data item is corrupting the allocated memory block in the multi_array object.

如果您将 ii_t<> 类更改为以下内容,您应该会获得更好的行为:

If you change the ii_t<> class to the following, you should get better behavior:

template<typename T>
struct ii_t: public iterator<input_iterator_tag, void, void, void, void>
{
  ii_t(std::istream& str)
    :m_str(&str)
  {}
  ii_t()
    :m_str(NULL)
  {}
  ii_t& operator++()   {return *this;}  // increment does nothing.
  ii_t& operator++(int){return *this;}
  T& operator*()
  {
    // On the de-reference we actuall read the data into a local //// static ////
    // Thus we can return a reference
    static T result;
    m_str->read(reinterpret_cast<char*>(&result),sizeof(T));
    return result;
  }
  // If either iterator has a NULL pointer then it is the end() of stream iterator.
  // Input iterators are only equal if they have read past the end of stream.
  bool operator!=(ii_t const& rhs)
  {
      // we need to make sure we're not just about to hit EOF
      // if we already haven't
      if (m_str && m_str->good()) {
        char dummy;
        m_str->read(&dummy,1);
        if (m_str->good()) {
            m_str->putback(dummy);
        }
      }

      if (rhs.m_str && rhs.m_str->good()) {
        char dummy;
        rhs.m_str->read(&dummy,1);
        if (rhs.m_str->good()) {
            rhs.m_str->putback(dummy);
        }
      }

      bool lhsPastEnd  = (m_str == NULL)     || (!m_str->good());
      bool rhsPastEnd  = (rhs.m_str == NULL) || (!rhs.m_str->good());

      return !(lhsPastEnd && rhsPastEnd);
  } 

  private:
    std::istream*   m_str;
};

相关更改在 bool operator!=(ii_t const& rhs) 函数中,如果需要,对包装的 istream<执行虚拟读取(然后撤消)/code> 来确定 istream 是否在 EOF.

The relevant changes are in the bool operator!=(ii_t const& rhs) function, where, if necessary, a dummy read is performed (then undone) on the wrapped istream to determine if the istream is at the EOF.

请注意,我并没有声称这是处理 EOF 情况的最佳技术,但它似乎有效.

Note that I'm making no claim that this is the best technique to handle the EOF situation, but it seems to work.

相关文章