I have a vector array of a class that's giving me some crap. I would beat it up, but that might result in some innocent circuits getting damaged.

Class:

class Font {
public:
  Font();
  ~Font();

  int style;
  int ptSize;
  std::string name;
  TTF_Font *font;
};

Font::Font()
{
  style = TTF_STYLE_NORMAL;
  ptSize = 0;
  name = "";
  font = NULL;
}

Font::~Font() 
{
  // Access violation
  TTF_CloseFont( font );
}

Code:

std::vector<Font> fonts;

SDL_Surface *renderText( std::string fontName, int ptSize, std::string text, const SDL_Color *textColor, const SDL_Color *backroundColor, int flags )
{
  // cut

  if( fontElement == -1 ) {
    std::string fileName = "c:\\windows\\fonts\\" + fontName;
		
    // class constructor called here
    fonts.resize( fonts.size() + 1 );
    fontElement = fonts.size() - 1;
    fonts[ fontElement ].ptSize = ptSize;
    fonts[ fontElement ].name = fontName;
    fonts[ fontElement ].font = TTF_OpenFont( fileName.c_str(), ptSize );
    if( fonts[ fontElement ].font == NULL ) {
      return NULL;
    }
		
    if( fontStyle != TTF_STYLE_NORMAL ) {
      fonts[ fontElement ].style = fontStyle;
      TTF_SetFontStyle( fonts[ fontElement ].font, fontStyle );
    }
  // class destructor called here
  }

  // cut

  // no error here
  if( flags & FH_BLENDED ) {
    return TTF_RenderText_Blended( fonts[ fontElement ].font, text.c_str(), fgColor );
  }
  else if( flags & FH_SHADED ) {
    return TTF_RenderText_Shaded( fonts[ fontElement ].font, text.c_str(), fgColor, bgColor );
  }
  else if( flags & FH_SOLID ) {
    return TTF_RenderText_Solid( fonts[ fontElement ].font, text.c_str(), fgColor );
  }

  return NULL;
}

The problem is that right after the if statement the class destructor is called. Oddly enough, when I use fonts[].font later, I don't get an error; I only get the access error after the program attempts to terminate, because it calls the destructor again. It goes something like this:

constructor
loads font
destructor
renders text - renders with a closed font??
back to main
display text - displays fine
destructor - error happens here

I can post the rest of the source code, if necessary. What stupid thing am I missing?

Recommended Answers

All 5 Replies

This is interesting. I have never really tried to insert elements into a vector in this fashion. I normally use the push_back() function to add values to the vector. I attempted to do what you are doing, and calling the resize() function calls the class constructor once and the destructor twice. And then the destructor is called once more when the main exits. Which would be very bad if you were using dynamically allocated elements in your class. I am not sure how this works internally, but is there a reason why you are using this logic instead of just adding elements to the vector using push_back() ?

class myClass{
public:
  myClass(){cout << "myclass constructor" << endl;}
  ~myClass(){cout << "myclass destructor" << endl;}
  int number;
};

int main ()
{
  vector<myClass> myVector;
  int element;
 
  myVector.resize(myVector.size() + 1);
  element = myVector.size() - 1;
  myVector[element].number = 100;
  myVector[element].number = 200;

  return 0; 
}

I used resize instead of push_back because push_back requires that you put in a value. If I were to declare another instance of Font, set all the variables, then use that in push_back(), it is my understanding that the pointers from both instances would point to the same object. Since the temporary class would call the destructor at the end of the if statement it would delete the object, leaving me with a dangling pointer. Alternatively, I could do:

Font temp;
fonts.push_back( temp );

It does work, but it just seems odd. Of course, I could be wrong cause I'm no expert on vector arrays.

If you wanted to you could use a vector of pointers instead of objects. That way you can create a new object as you needed it and add it to your vector. And then delete them all at the end.

vector<myClass*> myVector;
  myClass *tmp;
 
  for(unsigned int i = 0; i < 5; i++){
    tmp = new myClass(i);
    myVector.push_back(tmp);
  }

  // do stuff

  // delete any allocated pointers
  for (unsigned int i = 0; i < myVector.size(); i++){
    delete myVector[i];
  }

The problem with that approach is how my function works. Each time the program needs to display text, it calls renderText(). Loading a font takes my computer about 3 milliseconds, and I'm already worried about SDL going too slow. Thus, I opted to use a vector array of class 'Font', since vectors are easiest when it comes to expanding arrays, and each class can automatically close the TTF_Font* variable, plus I can use previously loaded fonts and I could do it all without the hassle of dynamic memory. Since no other function has access to the vector, I can't delete the class pointers in the vector at the end of the program.

Your response did get me thinking about some possible alternatives. I could make another flag to put in the flags parameter that would let the function know it has to delete the fonts; I could make a class which would contain the vector of pointers to the 'Font' class, making use of the class destructor to delete the vector; or I could give a void function access to the vector, so I could use atexit() to delete the vector (probably wouldn't work as the vector would probably be removed from memory prior to the atexit() call).

If you have any other ideas, please let me know, as mine kinda suck. I would still like to know why the vector is acting as it is, so I can avoid this in the future.

Well, I messed around with my code for a few hours, and I discovered that it wasn't actually a problem with the vector (as always, I blamed the other code first). The problem is by the time the program gets to the Font destructor, the TTF library has already quit. This is really quite annoying, since I closed the TTF library using atexit().

The problem now is getting the class destructor to run before the atexit stuff. With the code:

#include <iostream>

using namespace std;

class myClass {
public:
	myClass() { cout << "Constructor" << endl; }
	~myClass() { cout << "Destructor" << endl; }
};

myClass loser;

void func()
{
	cout << "Func" << endl;
}

int main()
{
	atexit( func );
	return 1;
}

the output will be "Constructor Func Destructor". Does anybody know a [non-messy] way around this?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.