Have you heard the phrase "coffee stain on the flip-down trays"? An airline CEO, while inspecting how his company handled airplane turnover, walked through the cabin and flipped down one of the tray tables. He saw coffee stains on the tray table. To the crew this was no big deal. They saw their job as cleaning out the cabin quickly to make way for the next set of passengers. The CEO saw it differently: "Coffee stains on the flip-down trays mean [to the passenger] that we do our engine maintenance wrong." It might be irrational, but those coffee stains on the tray tables mean passengers will look for another airline the next time they fly.

Your code has *lots* of coffee stains on the tray tables. Suppose you send code to be evaluated by an interviewer for some job. Your code might work, but those coffee stains on your code mean your job application will be filed circularly. (The circular file is the can everyone has next to their desk into which trash paper is discarded.) Don't take that chance. Get rid of those coffee stains.

No comments!
The only comment in your code is the one that says "I'm in the middle of writing this right now." Get into the habit of commenting all key components. The commentary should be one of the first things you write, not the last.

Each file should have a comment at the start of the file that addresses why the file exists, who wrote it, and who owns it. Here's a simple file header for your file:

Each member function should have a comment that briefly describes what it does, the arguments, and the return value (if it has one). Example:

Code (Text):

class BitPack {
...

/**
* Non-default constructor. All bits in the bit array are initialized to zero.
* @param nbits Number of bits in the bit array.
*/
BitPack(int nbits);

...
};

Each data member should have a comment saying why it exists. Example:

Code (Text):

class BitPack {
...

/**
* The bit array.
* @note This is allocated and deleted per the RAII idiom.
*/
usi* _booArr;

...
};

Regarding the comments I wrote: I'm using doxygen comments in the above. This is becoming the de facto standard for C++ documentation. The doxygen engine parses your comments and creates API documentation in html, LaTeX, and man page form. It's free.

BTW, I used the acronym RAII above. The person who is reviewing your code knows (or should know) what that means. You should, too.

#include <limits.h> and #include <assert.h>
This is C++. Use the C++ headers. You should have #included <climits> instead of <limits.h>, <cassert> instead of <assert.h>.

Macros.
Eschew macros in C++. You could have used a const static class member for this.

Inconsistent indentation in how you indented public and private.
My preference is to outdent public, protected, and private so they have the same indentation as the class statement. I do the same with case labels. I outdent anything that looks like a label. That's my preference, yours may vary. Whatever rule you do use, be consistent. Lack of consistency is a big coffee stain.

You have tabs in your source code. Don't do that.
You can use tabs while you are typing in your code if you can set your editor or IDE to automatically translate the tabs you type into the appropriate number of spaces.

Suppose you send your code to an interviewer for some job. She almost certainly will use a different editor with different tab settings than do you. Because your files contain tabs, when she opens your file she may well see garbage. This means your job application is also garbage. Don't take that chance.

You aren't following the Rule of Three.
The Rule of Three dictates that if you have a non-trivial destructor, copy constructor, or assignment operator, you almost certainly need all three. You have a non-trivial default constructor that allocates data. You are starting to follow RAII in that you do have a destructor, but you don't have a copy constructor or assignment operator. This will bite you someday. Get in the habit of declaring a copy constructor and assignment operator as soon as you declare a destructor.

Multiplication and division by 2 (in a loop!) instead of using the bit operators and bitmasks.
This is worse than a coffee stain on the tray table. It's a whole cup of coffee that was spilled on the tray table and then dripped onto and stained the carpet. This is unacceptable code. Use the bit operators (bitwise-and, bitwise-or, left shift, right shift) when you are dealing with bits.

Have you heard the phrase "coffee stain on the flip-down trays"? An airline CEO, while inspecting how his company handled airplane turnover, walked through the cabin and flipped down one of the tray tables. He saw coffee stains on the tray table. To the crew this was no big deal. They saw their job as cleaning out the cabin quickly to make way for the next set of passengers. The CEO saw it differently: "Coffee stains on the flip-down trays mean [to the passenger] that we do our engine maintenance wrong." It might be irrational, but those coffee stains on the tray tables mean passengers will look for another airline the next time they fly.

Your code has *lots* of coffee stains on the tray tables. Suppose you send code to be evaluated by an interviewer for some job. Your code might work, but those coffee stains on your code mean your job application will be filed circularly. (The circular file is the can everyone has next to their desk into which trash paper is discarded.) Don't take that chance. Get rid of those coffee stains.

Alright. I will.

[*]No comments!
The only comment in your code is the one that says "I'm in the middle of writing this right now." Get into the habit of commenting all key components. The commentary should be one of the first things you write, not the last.

Each file should have a comment at the start of the file that addresses why the file exists, who wrote it, and who owns it. Here's a simple file header for your file:

Each member function should have a comment that briefly describes what it does, the arguments, and the return value (if it has one). Example:

Code (Text):

class BitPack {
...

/**
* Non-default constructor. All bits in the bit array are initialized to zero.
* @param nbits Number of bits in the bit array.
*/
BitPack(int nbits);

...
};

Each data member should have a comment saying why it exists. Example:

Code (Text):

class BitPack {
...

/**
* The bit array.
* @note This is allocated and deleted per the RAII idiom.
*/
usi* _booArr;

...
};

Regarding the comments I wrote: I'm using doxygen comments in the above. This is becoming the de facto standard for C++ documentation. The doxygen engine parses your comments and creates API documentation in html, LaTeX, and man page form. It's free.

BTW, I used the acronym RAII above. The person who is reviewing your code knows (or should know) what that means. You should, too.

Will do. I really just started writing this and I considered comments to be the finishing touches. Plus, I'm probably going to change a lot of my procedures.

[*]#include <limits.h> and #include <assert.h>
This is C++. Use the C++ headers. You should have #included <climits> instead of <limits.h>, <cassert> instead of <assert.h>.

[*]Macros.
Eschew macros in C++. You could have used a const static class member for this.

Will do.

[*]Inconsistent indentation in how you indented public and private.
My preference is to outdent public, protected, and private so they have the same indentation as the class statement. I do the same with case labels. I outdent anything that looks like a label. That's my preference, yours may vary. Whatever rule you do use, be consistent. Lack of consistency is a big coffee stain.

Will do.

[*]You have tabs in your source code. Don't do that.
You can use tabs while you are typing in your code if you can set your editor or IDE to automatically translate the tabs you type into the appropriate number of spaces.

Suppose you send your code to an interviewer for some job. She almost certainly will use a different editor with different tab settings than do you. Because your files contain tabs, when she opens your file she may well see garbage. This means your job application is also garbage. Don't take that chance.

Good point. Will do.

[*]You aren't following the Rule of Three.
The Rule of Three dictates that if you have a non-trivial destructor, copy constructor, or assignment operator, you almost certainly need all three. You have a non-trivial default constructor that allocates data. You are starting to follow RAII in that you do have a destructor, but you don't have a copy constructor or assignment operator. This will bite you someday. Get in the habit of declaring a copy constructor and assignment operator as soon as you declare a destructor.

I'm going to have to remember this.

[*]Multiplication and division by 2 (in a loop!) instead of using the bit operators and bitmasks.
This is worse than a coffee stain on the tray table. It's a whole cup of coffee that was spilled on the tray table and then dripped onto and stained the carpet. This is unacceptable code. Use the bit operators (bitwise-and, bitwise-or, left shift, right shift) when you are dealing with bits.

The modern way to write code is to write the test code first -- before you write *any* of the actual code. This means the tests will initially fail, massively. The code won't even compile at first, let alone link or execute. That is deemed to be a good thing in test driven development. You have taken the first step toward "debugging the blank sheet of paper." (Your boss says "This sheet of paper has a complete design for your system. There's one minor bug: The page is blank. Fix that bug!")

You solve this problem one step at a time. The tests dictate the public interfaces. You now know what the class is supposed to do in a broad sense, what each public function is supposed to do. This gives enough information to write the public part of the class definition, along with rudimentary documentation. Now your test code will successfully compile! Phase I complete. It won't link, of course; that's the next step in the debugging a blank sheet of paper process.

Back to your code. I that see you've asked on another site how to create a copy constructor. Presumably you now know how to do that. The next step in the Rule of Three is to write an assignment operator. There are lots of gotchas with the assignment operator. Here's a particularly nasty one:

Code (Text):

BitPack bit_pack = BitPack(42);
bit_pack = bit_pack;

Who would do that? It doesn't matter that this is nonsense. Someday, someone will abuse your beautiful code just like that, if not worse. You need to defend against it. You can find all kinds of advice on the web on dealing with the self-assignment problem.

Another gotcha: You have dynamically allocated data in your BitPack class. Your assignment operator has to free the existing bitset, allocate a new one sized per the source object's bit set, and copy the contents of the source object's bitset into this newly allocated one. This is a royal pain.

There's a rather nifty solution that eliminates all this pain, the copy and swap paradigm. The prototype for a typical assignment operator is ClassName & operator=(const ClassName & source); With copy-and-swap you strike out the "const" and "&": The prototype is ClassName & operator=(ClassName source); You are receiving a copy of the source object rather than a reference or pointer to the source object. The implementation of the assignment operator is brutally simple with the copy-and-swap paradigm:

Here's how it works. The assignment operator receives a temporary that is a complete copy of object. That the argument is declared as ClassName source rather than ClassName & source ensures that this is a temporary. The copy constructor (you've written a good copy constructor, right?) will populate this temporary with a complete copy of the true source object. The destructor is called on this temporary when it goes out of scope. This happens at the semicolon in object_to_receive_copy = object_to_be_copied; Your copy-and-swap assignment operator takes advantage of this fact. Exchange (swap) all member data with that of the temporary and voila! you have a copy of the true source, and all the old data is properly taken care of.