简体   繁体   中英

C++ how to modify a 2D vector of objects size in a function initialized in the constructor?

Since I'm Italian, the function names are in Italian but really simple to understand: immagine=image, inserisci=insert, altezza=height, larghezza=width,mosaico =mosaic, righe=rows, colonne=columns.

So this program has 2 classes: an image with its attributes and a mosaic, which contains n images and this is represented through a 2D vector of obj Image (Immagine). The 2D vector has to be initialized in the constructor with r rows and c columns and using the inserisci (insert/add) function will then grow its dimension. Then if the element passed in the insert function has more rows/columns the insert function has to add the needed rows and columns in order to insert the element.

The problem is that even though I used pointers/references, every time I try to insert an element with a size that is bigger than the one initialized in the constructor, it gives me an error, meaning that the 2D vector that I modify in the insert function is not really edited... (look at the main when I insert: m2.inserisci(i4, 4, 4, &m2.immagini) since 4 rows > inital size of rows and same for columns gives me a runnning error..) Hope it is clear. This is my code:

#include <iostream>
#include <string>
#include <vector>
#include <sstream>

using namespace std;

class Immagine{
private:
        string nome;

public:
        int altezza;
        int larghezza;
        Immagine(string,int,int);
        string toString();
};
Immagine::Immagine(string n, int a, int l){
    nome = n;
    altezza = a;
    larghezza= l;
}
string Immagine::toString(){ 
    return nome;
        }

class Mosaico{
public:
    Mosaico(int, int,Immagine,vector< vector<Immagine> >*);

    int getRighe();
    int getColonne();
    string getImmagine(int,int);
    bool exist(int, int);
    Immagine getIm(int,int);
    void inserisci(Immagine,int,int,vector< vector<Immagine> >*);
    vector< vector<Immagine> > immagini;
    vector< vector<Immagine> >* aPointer= &immagini;
};
    Mosaico::Mosaico(int r, int c,Immagine imm, vector< vector<Immagine> >* immag ){
    (*immag).resize(r);
    for(int i=0; i<(*immag).size(); i++)
        for(int j=0; j<c; j++)
            (*immag)[i].insert((*immag)[i].begin()+j,imm);
}   
bool Mosaico::exist(int r, int c){
    for(int i = 0; i < getRighe(); i++){
        for(int j=0; j<getColonne(); j++){
            if(i==r && j==c && immagini[r][c].toString()!= " "){
                return true;
            }
        }
    }     
    return false;
}
int Mosaico::getRighe(){
    return immagini.size();
    }
int Mosaico::getColonne(){
    return immagini[1].size();
    }
string Mosaico::getImmagine(int r, int c){
    if(exist(r,c))
    return immagini[r][c].toString();
    }
Immagine Mosaico::getIm(int r, int c){
    return immagini[r][c];
}


void Mosaico::inserisci(Immagine imm,int r, int c, vector< vector<Immagine> >* immag){
        if(r<(*immag).size() && c<(*immag)[0].size()){
        (*immag)[r][c]=imm;
        }
        else if(r>=(*immag).size() && c>=(*immag)[0].size()){
            (*immag).resize(r);
            for(int i=0; i<r; i++){
                for(int j=(*immag)[0].size(); j<c; j++){
                    (*immag)[i].insert((*immag)[i].begin()+j, imm);
                }
            }
            (*immag)[r][c]=imm;
            }
        else if(r>=(*immag).size() && c<(*immag)[0].size()){
            (*immag).resize(r);
            (*immag)[r][c]=imm;
        }
    else if(r<(*immag).size() && c>=(*immag)[0].size()){
            for(int i=0; i<(*immag).size(); i++){
                for(int j=(*immag)[0].size(); j<c; j++){
                    (*immag)[i].insert((*immag)[i].begin()+j, imm);
                }
            }
            (*immag)[r][c]=imm;
            }

}

int main() {
    Immagine i1 ("I01",300,200);
    Immagine i2 ("I02",300,400);
    Immagine i3 ("I03",400,200);
    Immagine i4 ("I04",400,400);
    cout << "Creo un mosaico 2x2 con quattro immagini" <<endl;
    Mosaico m2(2,2,i1,&m2.immagini) ;
    cout<<m2.getRighe()<<endl;
    cout<<m2.getColonne()<<endl;
    for (int i=0; i < m2.getRighe(); i++) {
        for (int j=0; j < m2.getColonne(); j++){
            //if(m1.exist(i,j))
            cout<<m2.getImmagine(i,j);
        }
        cout<<endl;
    }
    m2.inserisci(i1, 0, 0, &m2.immagini);
    m2.inserisci(i2, 0, 1, &m2.immagini);
    m2.inserisci(i3, 1, 0, &m2.immagini);
    m2.inserisci(i4, 4, 4, &m2.immagini); //HERE IS WHERE I GET THE ERROR
    cout <<"Stampa mosaico: "<<endl;
    for (int i=0; i < m2.getRighe(); i++) {
        for (int j=0; j < m2.getColonne(); j++){
            cout<<m2.getImmagine(i,j);
        }
        cout<<endl;
    }
}

By the way, this was a Java exercise and I tried to do it in C++. Thanks in advance!

Before I'll get to the details of the issues, let me first state that there are a lot of things in the code I'd do differently. Most prominently, I'd probably use a flat vector<Image> for storage instead of a vector<vector<..>> . But such things are better suited for CodeReview in my opinion (once the code is working).


The biggest problems in the OP's code are within the implementation of the inserisci function:

 void Mosaico::inserisci(Immagine imm,int r, int c, vector< vector<Immagine> >* immag) { if(r < (*immag).size() && c < (*immag)[0].size()){ (*immag)[r][c]=imm; }

This part is fine, if we assume that (*immag)[i].size() is the same for all i in [0, (*immag).size()) . Let us call this assumption A. The [x, y) notation stands for a half-open-on-right interval (x is within that interval, y is not). Note that you can replace (*e).m with e->m , which I'll do in the following.

The assumption A is a class invariant: after every member function (except for the destructor), this class invariant must hold. Continuing with the inserisci function:

 else if(r>=(*immag).size() && c>=(*immag)[0].size()){ (*immag).resize(r);

The *immag vector now has r elements. This is insufficient if you want to access the r th element, since indexing starts with 0. You need to have at least r+1 elements. Replace the above resize with:

        int newRowCount = r+1;
        (*immag).resize(newRowCount);

Continuing with the OP's function:

 for(int i=0; i<r; i++){

This has the same off-by-one bug: replace r with newRowCount , or simply immag->size() .

         for(int i=0; i<immag->size(); i++){

Continuing with the OP's function:

 for(int j=(*immag)[0].size(); j<c; j++){ (*immag)[i].insert((*immag)[i].begin()+j, imm); } }

With the above resize , we have added newRowCount - immag->size() new elements to the immag vector. Those new elements are vectors of the size 0. To be able to access the c th element of such a vector, we need to add at least c+1 elements to it.

The value of (*immag)[0].size() however changes after the first iteration of the outer loop such that (*immag)[0].size() == c for the remaining (*immag)[i] elements where i is in [1, newRowCount) . This code won't add any new columns to those rows. A simple fix is:

            int newColumnCount = c+1;
            for(int j=(*immag)[i].size(); j < newColumnCount; j++){
                (*immag)[i].insert((*immag)[i].begin()+j, imm);
            }
        }
 (*immag)[r][c]=imm; }

A note related to code review: You can very easily resize the inner elements as well, using the resize-overload which takes an additional argument:

(*immag)[i].resize(newColumnCount, imm);

Continuing with the OP:

 else if(r>=(*immag).size() && c<(*immag)[0].size()){ (*immag).resize(r);

This suffers from the same off-by-one bug again. You need to have at least r+1 elements to access the r th element in the following

 (*immag)[r][c]=imm; }

And in the following piece of code, the same issues appear as in the second branch (that is, (*immag)[0].size() instead of referring to the current element's size, and j < c instead of j < newColumnCount ).

 else if(r<(*immag).size() && c>=(*immag)[0].size()){ for(int i=0; i<(*immag).size(); i++){ for(int j=(*immag)[0].size(); j<c; j++){ (*immag)[i].insert((*immag)[i].begin()+j, imm); } } (*immag)[r][c]=imm; } }

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