tags:

views:

112

answers:

2

When should I inline a member function and when should I use member initializers?

My code is below.. I would like to modify it so I could make use some inline when appropriate and member initializers:

#include "Books.h"

Book::Book(){
  nm = (char*)"";
  thck = 0;
  wght = 0;
}

Book::Book(const char *name, int thickness, int weight){
  nm =  strdup(name);
  thck = thickness;
  wght = weight;
}

Book::~Book(){

}

const char* Book::name(){
 return nm;
}

int Book::thickness(){
 return thck;
}

int Book::weight(){
 return wght;
}

//
// Prints information about the book using this format:
// "%s (%d mm, %d dg)\n"
//
void Book::print(){
  printf("%s (%d mm, %d dg)\n", nm, thck, wght);
}


Bookcase::Bookcase(int id){
 my_id = id;
 no_shelf = 0;
}

int Bookcase::id(){
 return my_id;
}

Bookcase::~Bookcase(){
  for (int i = 0; i < no_shelf; i++)
    delete my_shelf[i];
}

bool Bookcase::addShelf(int width, int capacity){
  if(no_shelf == 10)
    return false;
  else{
    my_shelf[no_shelf] = new Shelf(width, capacity);
    no_shelf++;
    return true;
  }
}

bool Bookcase::add(Book *bp){
 int index = -1;
 int temp_space = -1;
 for (int i = 0; i < no_shelf; i++){
    if (bp->weight() + my_shelf[i]->curCapacity() <= my_shelf[i]->capacity()){
       if (bp->thickness() + my_shelf[i]->curWidth() <= my_shelf[i]->width() && temp_space < (my_shelf[i]->width() - my_shelf[i]->curWidth())){
        temp_space = (my_shelf[i]->width()- my_shelf[i]->curWidth());
        index = i;
          }
    }
 }

 if (index != -1){
    my_shelf[index]->add(bp);
    return true;
 }else
    return false;

}

void Bookcase::print(){
 printf("Bookcase #%d\n", my_id);
 for (int i = 0; i < no_shelf; i++){
    printf("--- Shelf (%d mm, %d dg) ---\n", my_shelf[i]->width(), my_shelf[i]->capacity());
    my_shelf[i]->print();
 }
}
+3  A: 

Short member functions that are called frequently are good candidates for inlining. In order to make the member function "inlinable," you need to define it in the header file (either in the class definition itself, or below the class definition using the inline keyword).

You should always use constructor initializer lists to initialize member data. For user-defined types, this can make a substantial performance difference in some cases. Your constructor should look like this:

Book::Book() : nm(""), thck(0), wght(0) { }

Here is a pretty good explanation of why to use initializer lists.

+1  A: 

Short answer - not from the beginning. Declare clean interface for the class in the header, and put all implementation details into a .cpp file first. Measure, profile, and go from there.

As for initializers - use them always. Compiler does it for you anyway, so assigning data members in the constructor body is redundant (and might be expensive with class-type members.) There only few situations like member variable dependency and lower-level C calls when you need to explicitly do work in the constructor body.

Nikolai N Fetissov
"Compiler does it for you anyway..." Care to explain that?
@STingRaySC: Compiler inserts code to default-initialize all base classes (in order the appear after `class X:`) and member variables (in order they are declared) before the body of the constructor. The opposite happens *after* the body of the destructor - compiler inserts code to call destructors of the members, in reverse order, then the base destructors.
Nikolai N Fetissov
Only member variables of user-defined types are default initialized. That is exactly what makes assignment in the constructor body less efficient vs. initialization in the initializer list. For member data of built-in types, the members are not initialized by the compiler, so assigning to them in the constructor body is *not* redundant. Technically, even for UDTs, nothing is *redundant* because its default constructor will be called, followed by its assignment operator in the constructor body.
@STingRaySC: Yes, thanks for the built-in correction. The default constructor/assignment is "redundant" in terms of "unnecessary", not in terms of "identical".
Nikolai N Fetissov
To nit-pick, even whether or not it is *unnecessary* depends on how the class in question is designed. It may be that either the default constructor or the assignment operator have side effects that necessitate them both to run. Of course, this would arguably be bad design in the first place, but a possible situation nonetheless...