简体   繁体   中英

writing to a vector< vector<bool> >

I'm writing for class an implementation of Conway's Game of Life in a toroid. The function cargarToroide (loadToroid) should load from a file into the vector the appropriate status (alive or dead - True or False - 1 or 0) of each cell ( celda ), it's signature is as follows:

toroide cargarToroide(string nombreArchivo, bool &status);

nombreArchivo is the name of the file, and status should be false if there is any problem loading the file or in the format of the file.

The data structure is defined like this (I cannot change it):

typedef vector< vector<bool> > toroide;

the file is structured like this:

numberOfLines numberOfColums
list of the values of the cells
number of live cells

For example:

4 4
1 0 0 0
0 0 1 0
0 0 0 1
0 1 0 0
4

The thing is, I cannot find a way to make it work. I've read online that vector<bool> has problems when you try to load it the usual way, which was the first thing I've tried.

toroide cargarToroide(string nombreArchivo, bool &status)
{
    toroide t;
    ifstream fi (nombreArchivo);
    int cantidadFilas, cantidadColumnas;
    int celda;

    if(!fi){
        status = false;
    }

    fi >> cantidadFilas;
    fi >> cantidadColumnas;

    for(int i = 0; i < cantidadFilas; i++) {
        for (int j = 0; j < cantidadColumnas; j++) {
            fi >> celda;
            if(celda == 1) {
                t[i].push_back(true);
            }
            else if(celda == 0){
                t[i].push_back(false);
            }
            else{
                status = false;
                return t;
            }
        }
    }
    return t;
}

I've also tried defining celda as a boolean and just using

t[i].push_back(celda);

What would be the best way to approach this using C++11?

You need to resize the outer vector before you can use operator[] on it. You should also use the proper type (bool) when reading the data and check the input file for errors. I've commented in the code:

#include <iostream>
#include <fstream>
#include <vector>

typedef std::vector< std::vector<bool> > toroide;

// Both cargarToroide and cargarToroide_improved can be used
bool cargarToroide_improved(const std::string& nombreArchivo, toroide& in_toroide)
{
    std::ifstream fi(nombreArchivo);
    if(!fi) return false;

    int cantidadFilas, cantidadColumnas, liveCells=0;
    // use a bool to read the bool data
    bool celda;

    fi >> cantidadFilas;
    fi >> cantidadColumnas;
    // check if the stream is in a failed state
    if(fi.fail()) return false;

    // Temporary used to not mess with in_toroide until we're finished.
    // Create it with cantidadFilas default inserted rows
    toroide t(cantidadFilas);

    for(auto& row : t) {
        // default insert columns into the row
        row.resize(cantidadColumnas);
        for (int col = 0; col < cantidadColumnas; ++col) {
            fi >> celda;
            // check if the stream is in a failed state
            // (non-bool read or the file reached eof())
            if(fi.fail()) return false;
            // set column value in the row
            row[col] = celda;
            // count live cells
            liveCells += celda;
        }
    }

    // compare live cells in matrix with checksum
    int cmpLive;
    fi >> cmpLive;
    if(fi.fail() || cmpLive!=liveCells) return false;

    // a successful toroide was read, swap your temporary
    // toroide with the user supplied one
    std::swap(t, in_toroide);
    return true;
}

// if the signature of this function really can't be changed (which it should),
// make it a proxy for the function with a slightly nicer interface
// Like this:
toroide cargarToroide(std::string nombreArchivo, bool &status)
{
    toroide rv;
    status = cargarToroide_improved(nombreArchivo, rv);
    return rv;
}

Using the improved signature:

int main(int argc, char* argv[]) {
    std::vector<std::string> args(argv+1, argv+argc);

    for(auto& file : args) {
        toroide my_toroide;
        if(cargarToroide_improved(file, my_toroide)) {
            for(auto& r : my_toroide) {
                for(auto c : r) {
                    std::cout << c << " ";
                }
                std::cout << "\n";
            }
        } else {
            std::clog << "failed loading " << file << "\n";
        }
    }
}

Using the signature you're forced to use:

int main(int argc, char* argv[]) {
    std::vector<std::string> args(argv+1, argv+argc);

    for(auto& file : args) {
        bool status;
        toroide my_toroide = cargarToroide(file, status);
        if(status) {
            for(auto& r : my_toroide) {
                for(auto c : r) {
                    std::cout << c << " ";
                }
                std::cout << "\n";
            }
        } else {
            std::clog << "failed loading " << file << "\n";
        }
    }
}

If you know the number of rows at compile time (as you do in this case) you can use resize . In this case you will have to do the below before both the for loops.

t.resize(cantidadFilas);

In fact, you can do the same for the columns as well. Then you would no longer need to use push_back in the inner for loop as well.

If do not know the number of rows then you will just use push_back and add the rows to toroide . Then you would add the below lines before the second for loop.

vector<bool> row; 
t.push_back(row)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM