2

I am trying to write a simple game using C++ and SDL. My question is, what is the best practice to store class member variables.

MyObject obj;
MyObject* obj;

I read a lot about eliminating pointers as much as possible in similar questions, but I remember that few years back in some books I read they used it a lot (for all non trivial objects) . Another thing is that SDL returns pointers in many of its functions and therefor I would have to use "*" a lot when working with SDL objects.

Also am I right when I think the only way to initialize the first one using other than default constructor is through initializer list?

genpfault
  • 51,148
  • 11
  • 85
  • 139
davidv
  • 373
  • 5
  • 14

5 Answers5

2

Generally, using value members is preferred over pointer members. However, there are some exceptions, e.g. (this list is probably incomplete and only contains reason I could come up with immediately):

  1. When the members are huge (use sizeof(MyObject) to find out), the difference often doesn't matter for the access and stack size may be a concern.
  2. When the objects come from another source, e.g., when there are factory function creating pointers, there is often no alternative to store the objects.
  3. If the dynamic type of the object isn't known, using a pointer is generally the only alternative. However, this shouldn't be as common as it often is.
  4. When there are more complicated relations than direct owner, e.g., if an object is shared between different objects, using a pointer is the most reasonable approach.

In all of these case you wouldn't use a pointer directly but rather a suitable smart pointer. For example, for 1. you might want to use a std::unique_ptr<MyObject> and for 4. a std::shared_ptr<MyObject> is the best alternative. For 2. you might need to use one of these smart pointer templates combined with a suitable deleter function to deal with the appropriate clean-up (e.g. for a FILE* obtained from fopen() you'd use fclose() as a deleter function; of course, this is a made up example as in C++ you would use I/O streams anyway).

In general, I normally initialize my objects entirely in the member initializer list, independent on how the members are represented exactly. However, yes, if you member objects require constructor arguments, these need to be passed from a member initializer list.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • 1
    So I guess for object like Font (SDL_ttf) I use either smart pointer or maybe even better other object to wrap raw pointer and SDL function calls. – davidv Aug 30 '13 at 07:53
  • 1
    As suggested below by Vinicius Miranda – davidv Aug 30 '13 at 08:07
  • Don't forget that because SDL is a C library, you need to define custom "deleter class" for the smart pointers. I improved my answer to explain you that. – Vivian Miranda Aug 31 '13 at 01:24
  • number 2 is no longer a real big concern with c++11 move methods. – Cory-G Mar 17 '15 at 16:26
1

In case of initialization, it depends on what the options are, but yes, a common way is to use an initializer list.

The "don't use pointers unless you have to" is good advice in general. Of course, there are times when you have to - for example when an object is being returned by an API!

Also, using new will waste quite a bit of memory and CPU-time if MyObject is small. Each object created with new has an overhead of around 16-48 bytes in a typical modern OS, so if your object is only a couple of simple types, then you may well have more overhead than actual storage. In a largeer application, this can easily add up to a huge amount. And of course, a call to new or delete will most likely take some hundreds or thousands of cycles (above and beyond the time used in the constructor). So, you end up with code that runs slower and takes more memory - and of course, there's always some risk that you mess up and have memory leaks, causing your program to potentially crash due to out of memory, when it's not REALLY out of memory.

And as that famous "Murphy's law states", these things just have to happen at the worst possible and most annoying times - when you have just done some really good work, or when you've just succeeded at a level in a game, or something. So avoiding those risks whenever possible is definitely a good idea.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

First I would like to say that I completely agree with Dietmar Kühl and Mats Petersson answer. However, you have also to take on account that SDL is a pure C library where the majority of the API functions expect C pointers of structs that can own big chunks of data. So you should not allocate them on stack (you shoud use new operator to allocate them on the heap). Furthermore, because C language does not contain smart pointers, you need to use std::unique_ptr::get() to recover the C pointer that std::unique_ptr owns before sending it to SDL API functions. This can be quite dangerous because you have to make sure that the std::unique_ptr does not get out of scope while SDL is using the C pointer (similar problem with std::share_ptr). Otherwise you will get seg fault because std::unique_ptr will delete the C pointer while SDL is using it.

Whenever you need to call pure C libraries inside a C++ program, I recommend the use of RAII. The main idea is that you create a small wrapper class that owns the C pointer and also calls the SDL API functions for you. Then you use the class destructor to delete all your C pointers.

Example:

class  SDLAudioWrap {
  public:
  SDLAudioWrap() { // constructor
     // allocate SDL_AudioSpec
  }
  ~SDLAudioWrap() { // destructor
     // free SDL_AudioSpec
  }

  // here you wrap all SDL API functions that involve  
  // SDL_AudioSpec and that you will use in your program
  // It is quite simple
  void SDL_do_some_stuff() {
    SDL_do_some_stuff(ptr); // original C function 
                            // SDL_do_some_stuff(SDL_AudioSpec* ptr)
  }
  private: 
  SDL_AudioSpec* ptr;
}

Now your program is exception safe and you don't have the possible issue of having smart pointers deleting your C pointer while SDL is using it.

UPDATE 1: I forget to mention that because SDL is a C library, you will need a custom deleter class in order to proper manage their C structs using smart pointers.

Concrete example: GSL GNU scientific library. Integration routine requires the allocation of a struct called "gsl_integration_workspace". In this case, you can use the following code to ensure that your code is exception safe

 auto deleter= [](gsl_integration_workspace* ptr) {
   gsl_integration_workspace_free(ptr);
 };
 std::unique_ptr<gsl_integration_workspace, decltype(deleter)> ptr4 (
 gsl_integration_workspace_alloc (2000), deleter);

Another reason why I prefer wrapper classes

Vivian Miranda
  • 2,467
  • 1
  • 17
  • 27
0

Well, creating the object is a lot better than using pointers because it's less error prone. Your code doesn't describe it well.

MyObj* foo;
foo = new MyObj;
foo->CanDoStuff(stuff);
//Later when foo is not needed
delete foo;

The other way is

MyObj foo;
foo.CanDoStuff(stuff);

less memory management but really it's up to you.

Chemistpp
  • 2,006
  • 2
  • 28
  • 48
  • Thanks for answer, I know what is the difference, but I wanted to know what is recommended and/or more used in modern c++. – davidv Aug 29 '13 at 23:22
  • Well if you have no reason to allocate it dynamically, why do it? You leave yourself open to trying to access null pointers or memory leaks. Sometimes you cannot always avoid dynamic allocation, so when you do, just make sure you are aware of the implications. Then it's really about what fits the situation. – Chemistpp Aug 29 '13 at 23:24
0

As the previous answers claimed the "don't use pointers unless you have to" is a good advise for general programming but then there are many issues that could finally make you select the pointers choice. Furthermore, in you initial question you are not considering the option of using references. So you can face three types of variable members in a class:

MyObject obj;
MyObject* obj;
MyObject& obj;

I use to always consider the reference option rather than the pointer one because you don't need to take care about if the pointer is NULL or not.

Also, as Dietmar Kühl pointed, a good reason for selecting pointers is:

If the dynamic type of the object isn't known, using a pointer is generally the only alternative. However, this shouldn't be as common as it often is.

I think this point is of particular importance when you are working on a big project. If you have many own classes, arranged in many source files and you use them in many parts of your code you will come up with long compilation times. If you use normal class instances (instead of pointers or references) a simple change in one of the header file of your classes will infer in the recompilation of all the classes that include this modified class. One possible solution for this issue is to use the concept of Forward declaration, which make use of pointers or references (you can find more info here).

Community
  • 1
  • 1
piponazo
  • 478
  • 2
  • 4
  • 10