arrays in classes

Started by
10 comments, last by SiCrane 14 years, 4 months ago
Hi there, I'm trying to create a texture class, within it I want to have a two dimensional array of 'Colour' objects, as that is effectively what a texture is. However I'm encountering problems when trying to create the texture in the class. I tried to do this:

class Texture
{
public:
	Texture(int width, int height);
	Texture();

	Colour* texture;
};

However, whenever I try and create the array in the constructor, I get piles of errors.

Texture::Texture(int width, int height)
{
	Colour colourArray[width][height];
	texture = colourArray;
}

How can I create an array within a class, then fill it through the constructor?
Advertisement
Assuming this is C++, you seem to have some wrong ideas about the semantics of arrays and dynamic memory allocation.

Looking at this bit of code:
Texture::Texture(int width, int height){	Colour colourArray[width][height];	texture = colourArray;}
You didn't post the errors, but I'm guessing they refer to illegal array declarations and/or incompatible types. This would be closer:
Colour colourArray[width * height];texture = colourArray; // Array decays to pointer gracefully
Except that you can't declare variable-length built-in arrays in C++, and in any case it wouldn't help you because the pointer would become invalid as soon as the constructor completed execution.

What you want is something like this:
Texture::Texture(int width, int height) : texture(new Colour[width * height]){}
You will then need a destructor with a matching invocation of delete [].

Once you get comfortable with the details of dynamic memory management in C++, you'll probably want to instead use a proper RAII container, such as std::vector. Using a container class instead of managing the memory directly will make your code cleaner and more reliable, and will eliminate the need to define a constructor explicitly.
Thanks for the help, jyk. I'm assuming that if I just say

delete texture;


I will have a memory leak?
Quote:Original post by leet bix
I'm assuming that if I just say

delete texture;

I will have a memory leak?
In theory, you'll have undefined behaviour ;)
In practice, that behaviour will likely be a leak (but could be anything).

For that reason, always be sure that "p = new X" is matched with "delete p", and "p = new X[]" is matched with "delete [] p".

[edit]And just in case you're new to initialisation lists (the : thing), these two bits of code are pretty much the same thing:
Texture::Texture(int width, int height) : texture(new Colour[width * height]){}Texture::Texture(int width, int height){  texture = new Colour[width * height];}
[Edit #2]Keep in mind that when looking after dynamic allocations like this, the copy constructor and assignment operator will have to be defined as well, otherwise you can get leaks or double-deletion bugs.

The easiest way to handle this is to make your class "non copyable" by making the copy constructor and assignment operator private:
class Texture{public:	Texture() : texture(NULL) {}	Texture(int width, int height) :  : texture(new Colour[width * height]) {}	~Texture() { delete [] texture; }private:	Texture( const Texture& );//not implemented	Texture& operator=( const Texture& );//not implemented	Colour* texture;};
Something like this should do it:

class Texture {  typedef boost::multi_array<Colour, 2> Data;  typedef boost::shared_ptr<Data> Handle;  Handle texture;  Texture(Handle handle): texture(handle) {}  public:  Texture(int width, int height): texture(new Data(boost::extents[width][height])) {}  Colour& get(int x, int y) const { return (*Handle)[x][y]; }  void set(int x, int y, const Colour& c) { (*Handle)[x][y] = c; }  Texture copy() { return Texture(new Data(*Handle)); }}


This assumes that you don't actually want to copy the underlying texture data when you implicitly copy or assign a Texture. Sometimes that functionality is useful (e.g. to make another texture that's a slight variation), but having the copy constructor/assignment operator do it results in a lot of unexpected shuffling around of memory. That's why I've added it in explicitly: the copy constructor and assignment operator will leave both instances "sharing" the underlying data, but .copy() will create a new Texture with its own copy of the underlying data.
Thank you for the clarification. I'm going to go with Hodgman's method because I don't like using boost.
Quote:Thank you for the clarification. I'm going to go with Hodgman's method because I don't like using boost.
Note that in practice you'd probably be better off using std::vector, e.g. (not compiled or tested):
class Texture{    std::vector<Colour> data;public:    Texture(int width, int height) : data(width * height) {}};
This will obviate the need for a user-defined destructor and for worrying about the 'Rule of Three'. (Depending on what sort of semantics you want for your class, you could still disable copying as Hodgman demonstrated, or make the data shared as in Zahlman's example.)

Also, why don't you want to use Boost? I don't know that there's a particular need for it here (and I'm not one to push Boost arbitrarily), but quite often people seem to avoid it simply due to misconceptions about its nature (e.g. 'it's slow', even though much of it carries no run-time performance penalty, or 'it's huge', even though most of it is header-only and you can pick and choose which parts you want to use).

Anyway, the Boost libraries can be very handy, so I wouldn't toss them out entirely unless you have a sound reason for doing so.
I have nothing against boost, it seems to be used very widley, heck, if I had a dollar for everytime i saw shared_ptr on this forum I'd be rich! I'm just trying to use only the standard libraries to complete my entire project.
Quote:Original post by leet bix
I have nothing against boost, it seems to be used very widley, heck, if I had a dollar for everytime i saw shared_ptr on this forum I'd be rich! I'm just trying to use only the standard libraries to complete my entire project.
Fair enough :) Just keep in mind that a lot of Boost is 'practically' standard, and that some parts of it (e.g. shared_ptr) actually are part of the standard library now (although they may or may not be available as part of your implementation, depending on what compiler you're using).
Quote:Original post by leet bix
I have nothing against boost, it seems to be used very widley, heck, if I had a dollar for everytime i saw shared_ptr on this forum I'd be rich! I'm just trying to use only the standard libraries to complete my entire project.

Thats an odd goal to set for yourself. Why not try complete the project without a compiler for your next one? Plus I don't recall a way to implement Textures in standard C++, unless you want to render the scene to a file.

Setting arbitrary obstacles* for yourself is a little bit arrogant, though I totally know how you might not see that yet.

There was a time when I though boost was a little to "big" or "complex", and that I'd be better off without it. Just letting you know, as someone who has been in your shoes and come through the other side, it is only a matter of time. Better sooner than later.

* Especially against boost, which is the closest thing to the standard library there is for C++. Many of boost's features will be included in the next Standard C++ Library for C++ 0x (if and when its released).

This topic is closed to new replies.

Advertisement