Search code examples
c++filefstreammove-semanticsdynamic-allocation

Dynamic allocation of file data in C++


To be frank, I have an assignment that says, quite vaguely,

"If the file exists, the one-argument constructor allocates memory for the number of records contained in the file and copies them into memory."

Now, in considering this instruction, it would seem I am to allocate the dynamic memory /before/ copy the data over, and this seems in principle, impossible.

To dynamically allocate memory, to my knowledge, you require runtime definition of the size of the block to be reserved.

Given that the file size, or number of 'entries' is unknown, how can one possibly allocate that much memory? Does not the notion defeat the very purpose of dynamic allocation?

Solution wise, it would seem the only option is to parse the entire file, determining the size, allocate the proper amount of memory afterward, and then read through the file again, copying the data into the allocated memory.

Given that this must be a common operation in any program that reads file data, I wonder: What is the proper, or most efficient way of loading a file into RAM?

The notion of reading once to determine the size, and then again to copy seems very inefficient. I assume there is a way to jump to the end of the file to determine max length, which would make the process faster. Or perhaps using a static buffer and loading that in blocks to RAM?

Is it possible to read all of the data, and then move it into dynamic memory using the move operator? Or perhaps more efficient to use a linked list of some kind?


Solution

  • It all depends on file format. One way to store records is to first write how many records are stored in file. If you have two phone numbers your file might look like this:

    2
    Jon
    555-123
    Mary
    555-456
    

    In this case the solution is straightforward:

    // ...
    is >> count;
    record_type *record = new record_type[count];
    for ( int i = 0; i < count; ++i )
      is >> record[i].name >> record[i].number; // stream checks omitted
    // ...
    

    If the file does not store the number of records (I wouldn't do this), you will have to count them first, and then use the above solution:

    // ...
    int count = 0;
    std::string dummy;
    while ( is >> dummy >> dummy )
      ++count;
    is.clear();
    is.seekg( 0 );
    // ...
    

    A second solution for the second case, would be to write a dynamic container (I assume you are not allowed to use standard containers) and push the records as you read them:

    // ...
    list_type list;
    record_type r;
    while ( is >> r.name >> r.number )
      list.push_back( r );
    // ...
    

    The solutions are ordered by complexity. I did not compile the examples above.