compiler warning about class with no virtual constructor when there is one

I have this base class
1
2
3
4
5
6
7
8
9
10
11
12
13
class Netpbm {
protected:
  char magicNumber;
  int width;
  int height;
  Matrix<pixel> * pixels;
public:
  ...
  virtual ~Netpbm() {
    delete pixels;
  };
  ...
};


and this derived class:

1
2
3
4
5
6
7
8
class Bitmap : public Netpbm {
public:
  Bitmap(std::string file_name);
  virtual ~Bitmap() {};

  void read_file(std::string file_name);
  void write_file(std::string file_name);
};


In the main function, I use this class this way:

1
2
3
4
5
6
            Bitmap * image = new Bitmap(file_name.c_str());
            Surface * view = new Surface("image", image->getWidth(), image->getHeight());
            view->getRenderer()->setImage(image->toArray(), image->getWidth(), image->getHeight());
            view->loop();
            delete view;
            delete image;


But when I try compile the code, I got this warning:

 
warning: deleting object of polymorphic class type ‘Bitmap’ which has non-virtual destructor might cause undefined behavior [-Wdelete-non-virtual-dtor]


How I fix this?
What does your compiler do with this rather reduced version?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Netpbm {
public:
  virtual ~Netpbm() {}
};

class Bitmap : public Netpbm {
public:
  virtual ~Bitmap() {};
};

int main()
{
   Bitmap * B = new Bitmap;
   delete B;
}

with this reduced version, no error or warning is issued.
Why is pixels a pointer? As per your previous thread and my refactored code
https://cplusplus.com/forum/beginner/285116/

you only need dynamic memory in Matrix class. This makes things much easier!
with this reduced version, no error or warning is issued.


Can you produce a minimal compilable code using just these classes that does show the warning?
With the refactored code sugested, I compile the code with no error or warnings, but when I try run the program, it cannot access the memory address for the base class atributes (from the derived class, I supose). the debugger (gdb) shows this message:

1
2
3
4
5
6
7
8
9
Thread 1 "game2d" received signal SIGSEGV, Segmentation fault.
0x000055555556dc40 in Matrix<Pixel>::getHeight (this=0x19) at src/matrix.hpp:47
47              return height;
(gdb) backtrace
#0  0x000055555556dc40 in Matrix<Pixel>::getHeight (this=0x19) at src/matrix.hpp:47
#1  0x000055555556d7dc in Netpbm::toArray (this=0x1) at src/netpbm.cpp:9
#2  0x000055555556ccd7 in main (argc=<error reading variable: Cannot access memory at address 0x7fffffffdacc>, 
    argv=<error reading variable: Cannot access memory at address 0x7fffffffdac0>) at src/Main.cpp:22
Backtrace stopped: Cannot access memory at address 0x7fffffffdd18


For this error, can you provide a main() which only uses Matrix, Bitmap and Netpbm which gives the error so that I can have a look. As I said with that code, it hadn't been very much tested.

PS Also a test file to read from. Without one, that's why I didn't do much testing.

Last edited on
This code gives the same error, for what I could test here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <sstream>

#include "netpbm.hpp"

class Image {
private:
    float * vertexList;
    int width;
    int height;
public:
    Image(float * v, int w, int h) {
        vertexList = v;
        width = w;
        height = h;
    }

    ~Image() {
        delete vertexList;
    }
};

class Renderer {
private:
    Image * image;
public:
    Renderer() {
        image = NULL;
    };
    
    ~Renderer() {
        delete image;
    };

    void setImage(float * vertices, int width, int height) {
        image = new Image(vertices, width, height);
    };
};

class Surface {
private:
    int width;
    int height;
    Renderer * renderer;
public:
    Surface(std::string windows_title, int w, int h) {
        width = w;
        height = h;
        renderer = new Renderer();
    };
    ~Surface() {
        delete renderer;
    };

    Renderer * getRenderer() {
        return renderer;
    };

    void loop() {
        //
    }
};

int main(int argc, char ** argv) {
    if (argc < 2) {
        std::cout << "Usage: game <file_name>" << std::endl;
        return 1;
    }

    std::string file_name(argv[1]);
    std::string extension;
    
    std::stringstream ss(file_name);
    while(getline(ss, extension, '.'));

    if(extension == "pbm") {
        Bitmap image(file_name.c_str());
        Surface * view = new Surface("image", image.getWidth(), image.getHeight());
        view->getRenderer()->setImage(image.toArray(), image.getWidth(), image.getHeight());
        view->loop();
        delete view;
    }

    return 0;
}


I compile the code with this command:

 
g++ -I /.../include/ example3.cpp -o example -L /.../ -l:libnetpbm.a


the code for the library is the one in the previous posts.

ANd I use this file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
P1
32 32
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Using the file from above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#include <algorithm>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>

using pxArray = std::vector<float>;

template <class T>
class Matrix {
private:
	size_t height {};
	size_t width {};
	T** values {};

public:
	Matrix() = default;

	Matrix(size_t h, size_t w) : height(h), width(w), values(new T* [height]) {
		for (size_t ht {}; ht < h; ++ht)
			values[ht] = new T[width] {};
	}

	Matrix(const Matrix& old) : Matrix(old.height, old.width) {
		for (size_t ht {}; ht < height; ++ht)
			std::copy_n(old.values[ht], width, values[ht]);
	}

	Matrix(Matrix&& old) noexcept {
		swap(old);
	}

	Matrix& operator=(Matrix old) noexcept {
		swap(old);
		return *this;
	}

	size_t getHeight() const {
		return height;
	}

	size_t getWidth() const {
		return width;
	}

	~Matrix() {
		clear();
	}

	void swap(Matrix& old) noexcept {
		std::swap(height, old.height);
		std::swap(width, old.width);
		std::swap(values, old.values);
	}

	void clear() {
		for (size_t i {}; i < height; ++i)
			delete[] values[i];

		delete[] values;
		height = width = 0;
		values = nullptr;
	}

	T* operator[](size_t index) {
		return values[index];
	}

	const T* operator[](size_t index) const {
		return values[index];
	}
};

struct Pixel {
	float r {}, g {}, b {};
};

class Netpbm {
protected:
	char magicNumber {};
	Matrix<Pixel> pixels;

public:
	virtual ~Netpbm() {}

	char getMagicNumber() const {
		return magicNumber;
	}

	size_t getWidth() const {
		return pixels.getWidth();
	}

	size_t getHeight() const {
		return pixels.getHeight();
	}

	pxArray toArray() const;

	virtual bool read_file(const std::string& file_name) = 0;
	//virtual void write_file(const std::string& file_name) = 0;
};

class Bitmap : public Netpbm {
public:
	Bitmap(const std::string& file_name) {
		readOK = read_file(file_name);
	}

	// OR use throw with exception handling
	bool openOK() const {
		return readOK;
	}

	//void write_file(const std::string& file_name) override;

private:
	bool readOK {};
	bool read_file(const std::string& file_name) override;
};

pxArray Netpbm::toArray() const {
	pxArray result(pixels.getWidth() * pixels.getHeight() * 5);

	// For testing - displays the pixel matrix
	//for (size_t i {}; i < pixels.getHeight(); ++i)
		//for (size_t j {}; j < pixels.getWidth(); ++j)
			//std::cout << pixels[i][j].b << ' ' << pixels[i][j].g << ' ' << pixels[i][j].b << '\n';

	for (size_t i {}, count {}; i < pixels.getHeight(); ++i)
		for (size_t j {}; j < pixels.getWidth(); ++j) {
			// NOTE THIS IS INTEGER DIVISION!!!!
			const auto x { float(j) / pixels.getWidth()}, y {float(i) / pixels.getHeight()};

			result[count++] = - 1 + (2 * x);
			result[count++] = 1 - (2 * y);
			result[count++] = pixels[i][j].r;
			result[count++] = pixels[i][j].g;
			result[count++] = pixels[i][j].b;
		}

	return result;
}

bool Bitmap::read_file(const std::string& file_name) {
	std::ifstream file(file_name);

	if (!file)
		return false;

	size_t h {}, w {};

	for (std::string line_one; std::getline(file, line_one); )
		if (line_one.size() >= 2 && line_one[0] != '#') {
			magicNumber = line_one[1];
			break;
		}

	for (std::string line_two; std::getline(file, line_two); )
		if (!line_two.empty() && line_two[0] != '#') {
			std::stringstream ss(line_two);

			ss >> w >> h;
			pixels = Matrix<Pixel>(h, w);
			break;
		}

	// Make sure we're read some values!
	if (magicNumber == char {} || h == 0 || w == 0)
		return false;

	if (magicNumber == '1' || magicNumber == '4') {
		std::vector<Pixel> v;

		if (magicNumber == '1') {
			for (std::string line_pixels; std::getline(file, line_pixels); )
				if (!line_pixels.empty() && line_pixels[0] != '#') {
					std::stringstream ss(line_pixels);

					for (float p; ss >> p; v.emplace_back(p, p, p));
				}
		} else
			for (unsigned char data {}; file.read(reinterpret_cast<char*>(&data), 1); )
				for (int i {}; i < 8; ++i)
					if (data & (1 << i))
						v.emplace_back(1.f, 1.f, 1.f);
					else
						v.emplace_back(0.f, 0.f, 0.f);

		if (v.size() < h * w)
			return false;

		for (size_t i {}, counter {}; i < h; ++i)
			for (size_t j {}; j < w; ++j)
				pixels[i][j] = v[counter++];
	}

	return true;
}

int main() 	{
	Bitmap bm("test.bm");

	if (!bm.openOK())
		return (std::cout << "Problem opening/reading file\n"), 1;

	const auto arr { bm.toArray() };

	std::cout << arr.size() << '\n';
}


for VS, displays 5120
Working with the Matrix class do not work for me, then I tried remove it and got this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
struct Pixel {
    float r, g, b;
};
typedef struct Pixel pixel;

class Netpbm {
protected:
  std::vector<std::vector<pixel>> pixels;
public:
  virtual void read_file(std::string file_name) = 0;
  virtual void write_ascii_file(std::string file_name) = 0;
  virtual void write_binary_file(std::string file_name) = 0;

  int getHeight();
  int getWidth();
  std::vector<float> toArray();
};

int Netpbm::getHeight() { return pixels.size(); };

int Netpbm::getWidth() { return pixels[0].size(); };

std::vector<float> Netpbm::toArray() {
  std::vector<float> result;
  size_t h = pixels.size(), w = pixels[0].size();

  for(size_t i=0; i<h; i++) {
    for(size_t j=0; j<w; j++) {
      float x = j/w, y=i/h;
      result.push_back(-1 + (2 * x));
      result.push_back(1 - (2 * y));
      result.push_back(pixels[i][j].r);
      result.push_back(pixels[i][j].g);
      result.push_back(pixels[i][j].b);
    }
  }

  return result;
}

class Bitmap : public Netpbm {
public:
  void read_file(std::string file_name);
  void write_ascii_file(std::string file_name);
  void write_binary_file(std::string file_name);
};

void Bitmap::read_file(std::string file_name) {
  std::ifstream file(file_name);
  std::string line_one, line_two, line_pixels;
  char magicNumber;
  std::string width, height;

  while(getline(file, line_one)) {
    if(line_one.size() > 0 && line_one.at(0) != '#') {
      magicNumber = line_one.at(1);
      break;
    }
  }

  while(getline(file, line_two)) {
    if(line_two.size() > 0 && line_two.at(0) != '#') {
      std::stringstream ss(line_two);
      getline(ss, width, ' ');
      getline(ss, height, ' ');
      break;
    }
  }

  if(magicNumber == '1') {
    std::vector<pixel> v;

    while(getline(file, line_pixels)) {
      if(line_pixels.size() > 0 && line_pixels.at(0) != '#') {
        std::stringstream ss(line_pixels);
        std::string value;
        while(getline(ss, value, ' ')) {
          pixel p;
          p.r = p.g = p.b = stoi(value);
          v.push_back(p);
        }
      }
    }

    int counter = 0;
    for(int i=0; i<stoi(height); i++)
      for(int j=0; j<stoi(width); j++)
        pixels[i][j] = v[counter++];
  }

  if(magicNumber == '4') {
    std::vector<pixel> v;

    while(!file.eof()) {
      unsigned char data[1];
      file.read((char*)data, 1);
      for(int i=0; i<8; i++) {
        pixel p;
        if(data[0]&(1<<i))
          p.r = p.g = p.b = 1;
        else
          p.r = p.g = p.b = 0;
        v.push_back(p);
      }
    }

    int counter = 0;
    for(int i=0; i<stoi(height); i++)
      for(int j=0; j<stoi(width); j++)
        pixels[i][j] =  v[counter++];
  }
}


My main function is something like that:

1
2
3
4
5
6
7
8
9
10
            Bitmap image;
            image.read_file(file_name);
            std::cout << "width: " << image.getWidth() << std::endl;
            std::cout << "height: " << image.getHeight() << std::endl;
            for(int i=0; i<image.getHeight(); i++) {
                for(int j=0; j<image.getWidth(); j++) {
                    std::cout << image.toArray()[i*j + j];
                }
                std::cout << std::endl;
            }


Now, when I compile and run the programa O got this error:

1
2
3
4
5
6
Program received signal SIGSEGV, Segmentation fault.
0x000055555556ee27 in Bitmap::read_file (this=0x7fffffffdae8, file_name="teste.pbm") at src/bitmap.cpp:43
43              pixels[i][j] = v[counter++];
(gdb) backtrace
#0  0x000055555556ee27 in Bitmap::read_file (this=0x7fffffffdae8, file_name="teste.pbm") at src/bitmap.cpp:43
#1  0x000055555556cba4 in main (argc=2, argv=0x7fffffffde28) at src/Main.cpp:20 

Do you realize that pixels[i][j] will not automatically insert the elements if they don't exist?
Last edited on
I did not realize that, but I have tried pixels[i].push_back(v[counter++] too, and I still got an error in this case.
I am now using this:

1
2
3
4
5
6
7
8
9
    int counter = 0;
    for(int i=0; i<stoi(height); i++) {
      std::vector<pixel> row;
      for(int j=0; j<stoi(width); j++) {
        row.push_back(v[counter++]);
      }
      pixels.push_back(row);
    }
  }


but height and width aren´t displaying the expect value (when I execute the main function above).
Working with the Matrix class do not work for me


Why - works OK for me...

With minimial changes to the OP code posted above:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>

struct Pixel {
	float r, g, b;
};

typedef struct Pixel pixel;

class Netpbm {
protected:
	std::vector<std::vector<pixel>> pixels;
public:
	virtual void read_file(std::string file_name) = 0;
	//virtual void write_ascii_file(std::string file_name) = 0;
	//virtual void write_binary_file(std::string file_name) = 0;

	int getHeight();
	int getWidth();
	std::vector<float> toArray();
};

int Netpbm::getHeight() {
	return pixels.size();
};

int Netpbm::getWidth() {
	return pixels.size() > 0 ? pixels[0].size() : 0;
};

std::vector<float> Netpbm::toArray() {
	std::vector<float> result;
	size_t h = pixels.size(), w = pixels.size() > 0 ? pixels[0].size() : 0;

	for (size_t i = 0; i < h; i++) {
		for (size_t j = 0; j < w; j++) {
			float x = j / w, y = i / h;

			result.push_back(-1 + (2 * x));
			result.push_back(1 - (2 * y));
			result.push_back(pixels[i][j].r);
			result.push_back(pixels[i][j].g);
			result.push_back(pixels[i][j].b);
		}
	}

	return result;
}

class Bitmap : public Netpbm {
public:
	void read_file(std::string file_name);
	//void write_ascii_file(std::string file_name);
	//void write_binary_file(std::string file_name);
};

void Bitmap::read_file(std::string file_name) {
	std::ifstream file(file_name);
	std::string line_one, line_two, line_pixels;
	char magicNumber;
	std::string width, height;

	while (getline(file, line_one)) {
		if (line_one.size() > 1 && line_one.at(0) != '#') {
			magicNumber = line_one.at(1);
			break;
		}
	}

	while (getline(file, line_two)) {
		if (line_two.size() > 2 && line_two.at(0) != '#') {
			std::stringstream ss(line_two);

			getline(ss, width, ' ');
			getline(ss, height, ' ');
			break;
		}
	}

	pixels.resize(stoi(height));
	for (int i = 0; i < pixels.size(); ++i)
		pixels[i].resize(stoi(width));

	if (magicNumber == '1') {
		std::vector<pixel> v;

		while (getline(file, line_pixels)) {
			if (line_pixels.size() > 0 && line_pixels.at(0) != '#') {
				std::stringstream ss(line_pixels);
				std::string value;

				while (getline(ss, value, ' ')) {
					pixel p;

					p.r = p.g = p.b = stoi(value);
					v.push_back(p);
				}
			}
		}

		int counter = 0;

		for (int i = 0; i < stoi(height); i++)
			for (int j = 0; j < stoi(width); j++)
				pixels[i][j] = v[counter++];
	}

	if (magicNumber == '4') {
		std::vector<pixel> v;

		while (!file.eof()) {
			unsigned char data[1];
			file.read((char*)data, 1);
			for (int i = 0; i < 8; i++) {
				pixel p;
				if (data[0] & (1 << i))
					p.r = p.g = p.b = 1;
				else
					p.r = p.g = p.b = 0;
				v.push_back(p);
			}
		}

		int counter = 0;
		for (int i = 0; i < stoi(height); i++)
			for (int j = 0; j < stoi(width); j++)
				pixels[i][j] = v[counter++];
	}
}

int main() {
	Bitmap image;
	image.read_file("test.bm");

	std::cout << "width: " << image.getWidth() << std::endl;
	std::cout << "height: " << image.getHeight() << std::endl;

	for (int i = 0; i < image.getHeight(); i++) {
		for (int j = 0; j < image.getWidth(); j++) {
			std::cout << image.toArray()[i * j + j];
		}
		std::cout << std::endl;
	}
}


...howver this has several warnings re possible loss of data!! There is much scope for code improvement! And what is L143 supposed to do????

This displays:


width: 32
height: 32
-11111-11000-11000-11000-11000-11000-11
-11110-10010-10010-11110-11110-10010-10
-11100-10100-11101-10100-10101-10110-10
-11001-10011-11001-10011-11001-10011-11
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11000-11100-11101-11001-11000-11100-11
-10010-11010-10110-11010-10110-10011-10
-10101-10101-10101-10101-10101-10101-10
-10001-10011-10001-10111-10001-11101-10
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11011-11000-11001-11000-11100-11000-11
-10010-11110-10010-11110-10010-11110-10
-10100-10100-10100-10110-11101-10110-11
-10011-11011-11001-10001-10011-11011-11
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11100-11100-11100-11100-11100-11100-11
-10110-10011-10110-11011-10010-11010-10
-10101-10101-10110-10110-10101-10101-10
-10001-11011-10001-10101-10001-10101-10
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11101-11000-11010-11000-11010-11000-11
-10110-10110-11010-11010-10110-10110-11
-10100-10100-10101-10100-11101-10110-11
-10011-10011-10011-10011-10011-10011-10
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11000-11001-11101-11100-11000-11001-11
-10010-11011-10110-11011-10110-10010-10
-10111-10100-10111-10100-10111-10100-10
-10001-10111-10001-10011-10001-11001-10
-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1-1
-11001-11000-11011-11000-11110-11000-11
-11010-11010-11010-11010-11010-11010-11

Last edited on
For main() do you mean something like ??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main() {
	Bitmap image;
	image.read_file("test.bm");

	std::cout << "width: " << image.getWidth() << '\n';
	std::cout << "height: " << image.getHeight() << '\n';

	const auto toarr { image.toArray() };

	for (size_t i {}; i < toarr.size(); i += 5) {
		for (size_t k {}; k < 5; ++k)
			std::cout << toarr[i + k] << ' ';

		std::cout << '\n';
	}
}

As a first refactor of this, consider:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <sstream>

struct Pixel {
	float r {}, g {}, b {};
};

class Netpbm {
protected:
	std::vector<std::vector<Pixel>> pixels;

public:
	virtual bool read_file(const std::string& file_name) = 0;
	//virtual void write_ascii_file(std::string file_name) = 0;
	//virtual void write_binary_file(std::string file_name) = 0;

	size_t getHeight() const;
	size_t getWidth() const ;
	std::vector<float> toArray();
};

size_t Netpbm::getHeight() const {
	return pixels.size();
};

size_t Netpbm::getWidth() const {
	return pixels.size() > 0 ? pixels[0].size() : 0;
};

std::vector<float> Netpbm::toArray() {
	const size_t h { getHeight() }, w { getWidth() };
	std::vector<float> result;

	result.reserve(h * w * 5);

	for (size_t i {}; i < h; ++i) {
		for (size_t j {}; j < w; ++j) {
			const auto x { float(j) / w }, y { float(i) / h };

			result.push_back(-1 + (2 * x));
			result.push_back(1 - (2 * y));
			result.push_back(pixels[i][j].r);
			result.push_back(pixels[i][j].g);
			result.push_back(pixels[i][j].b);
		}
	}

	return result;
}

class Bitmap : public Netpbm {
public:
	bool read_file(const std::string& file_name);
	//void write_ascii_file(std::string file_name);
	//void write_binary_file(std::string file_name);
};

bool Bitmap::read_file(const std::string& file_name) {
	std::ifstream file(file_name);

	if (!file)
		return false;

	char magicNumber {};
	size_t w {}, h {};

	for (std::string line_one; std::getline(file, line_one); )
		if (line_one.size() > 1 && line_one[0] != '#') {
			magicNumber = line_one[1];
			break;
		}

	for (std::string line_two; getline(file, line_two); )
		if (line_two.size() > 2 && line_two[0] != '#') {
			std::stringstream ss(line_two);

			ss >> w >> h;
			break;
		}

	if (magicNumber == char {} || w == 0 || h == 0)
		return false;

	pixels.resize(h);
	for (size_t i {}; i < pixels.size(); ++i)
		pixels[i].resize(w);

	if (magicNumber == '1' || magicNumber == '4') {
		std::vector<Pixel> v;

		auto req { w * h };

		if (magicNumber == '1') {
			for (std::string line_pixels; std::getline(file, line_pixels); )
				if (line_pixels.size() > 0 && line_pixels[0] != '#') {
					std::stringstream ss(line_pixels);

					for (float p; ss >> p; --req)
						v.emplace_back(p, p, p);
				}
		} else
			for (unsigned char data {}; file.read(reinterpret_cast<char*>(&data), 1); req -= 8)
				for (unsigned i {}; i < 8; ++i)
					if (data & (1 << i))
						v.emplace_back(1.f, 1.f, 1.f);
					else
						v.emplace_back(0.f, 0.f, 0.f);

		if (req)
			return false;

		for (size_t i {}, counter {}; i < h; ++i)
			for (size_t j {}; j < w; ++j)
				pixels[i][j] = v[counter++];

		return true;
	}

	return false;
}

int main() {
	Bitmap image;

	if (!image.read_file("test.bm"))
		return (std::cout << "Cannot open/read file\n"), 1;

	std::cout << "width: " << image.getWidth() << '\n';
	std::cout << "height: " << image.getHeight() << '\n';

	const auto toarr { image.toArray() };

	std::cout << "size of toArray: " << toarr.size() << '\n';

	for (size_t i {}; i < toarr.size(); i += 5) {
		for (size_t k {}; k < 5; ++k)
			std::cout << toarr[i + k] << ' ';

		std::cout << '\n';
	}
}

With this code, the same error happens, but now with the line 87: pixels.resize(h);.
Topic archived. No new replies allowed.