Sunday, March 25, 2012

Redemption

So, we had our second test in OOP last week, and I would like to take the time to give a little feedback about it via Dr. Downing's request. I feel as though I did much better on that test than the first, coming out of the test feeling much more confident than I did with the first. For this particular test, I studied and focused far more on understanding the slides and quizzes rather than simply trying to memorize them. Really sitting down and trying to understand the difference between the different iterators and what was really happening in the examples proved to be very useful.

In some of the previous projects me and various partners ventured out a bit and tried our hands at declaring objects on the heap, even going so far as to create custom linked lists and understand how to manage them correctly. I think doing that and understanding what was going on during the construction and destruction of objects did a lot in helping to explain the two part process that happens when deallocating objects. That is, the objects are deleted and the memory the objects possessed is then freed.

I do think the test may have been a little one-sided on certain subjects. Many people said that if one did not understand one question, he or she would very likely not understand the surrounding three or four questions. I find this somewhat true, but I also believe that one could logically infer the answer from the other questions. Or rather, one could infer the logic to answer a question from analyzing similar questions.

One question I like to ask myself when asked questions dealing with language semantics pertains to asking how the language would act in certain situations if I wrote it. After all, programming languages are designed to be as eloquent and logical as possible, and in my opinion should have predictable functionality to the programmer. Then again, C++ can be very, very complicated, but I will take any mindset I can get that gives me more confidence in a test.

Sunday, March 18, 2012

The Beauty of Lists

So, if you take a look at my last post, you can see that I have taken a liking to the use of vectors over arrays in C++. While the current project in OOP naturally calls for a "has-many" relationship between two classes, I have found that there are other, possibly better options to use than vectors.

Lists, under the right circumstance, can prove to be a good option when random access is not required. This last week in another project from an operating systems course, a situation called for use of a linked list. It required a list of objects that was sorted under some characteristic defined in the class, and it required that addition of elements be as cheap as possible. Well, it turns out the C++ STL has a wonderfully built list already that I have only begun to scratch the surface of. In order to maintain the list in sorted order, it is as simple as overloading the "<" operator, pushing an object to the front of the list and then simply calling the sort function from list. i.e. someList.push_front(someObject) and then doing someList.sort(). While sorting vectors typically involves copying, for lists all that is required is rearrangement. Or in the words of the C++ reference:


The entire operation does not involve the construction, destruction or copy of any element object. They are moved within the container.


Sorting a vector, on the other hand, typically calls for the use of algorithm's sort unless a custom sort is created, but I really do not see why you would when creating comparison functions and using built-in sorts are so easy.

Some might argue that inserting into a list is actually more expensive than inserting into a vector. In some cases I could see this, because for small types it is extremely simple for the L2 cache to do its work on the entire vector (say if we are pushing to the front of the vector). For larger objects, as containers grow in size, this could prove to be a problem as the amount of copy calls grows. 


I would love to hear some points on the efficiencies of vectors vs. lists in the comments!

Monday, March 12, 2012

The Beauty of Vectors

After months of only using arrays in C++, I have recently started using vectors as my go-to basic data structure. While arrays are great for lower level code and tasks that require the highest level of efficiency, in most cases vectors will prove to handle things in a much simpler and more elegant way. I personally like that vectors provide the user with a way to retrieve the size of the vector. It is no longer needed to keep track of the size of an array with a separate variable, which can really make vectors easier to work with.

Often times when using simple arrays it can be a nuisance to deal with managing the objects they hold. Vectors also work magically with memory. When vectors go out of scope, it calls the destructor on the elements it holds. I would argue that using a smarter container like vector instead of an array decreases development time because it helps reduce programming errors.

One of the interesting caveats involved with using vectors is the way iterating is handled. At first glance, it can be easy to assume that a simple for loop from int i = 0 to some_vector.size() would work just fine.

for (int i = 0; i < someVector.size(); ++i)
    cout << someVector[i] << " ";

Well, it does, but the field that holds the size in vector is unsigned, so a type warning occurs at compile time, and that means there is probably a better way to do it. The first, simple fix, is to simply change the type of 'i' in the loop to an unsigned type so that the comparison i < someVector.size() will not result in a warning. Unsigned int will do, but it turns out vector actually uses the size_t type for this purpose, and that ends up being a far more correct solution than simply using an unsigned specified type.

for (size_t i = 0; i < someVector.size(); ++i)
    cout << someVector[i] << " ";

We can still do better by using iterators instead of using the standard for loop. Vectors have both a begin() method and an end() method that both return iterators. (Obviously begin returns an iterator to the beginning of the vector and end returns an iterator to the end). Hell, we could even use rbegin and rend which return reverse iterators. Here is the simplest way to use them in one for loop:

for (vector<T>::iterator it = someVector.begin(); it != someVector.end(); ++i)
    cout << *it << " ";

Notice that in this case we had to dereference the iterator object since it is simply pointing to the consecutive elements in someVector.

Anyways, vectors are proving themselves to be a very, very cool alternative to arrays. When using them just be careful that you initialize them properly if the initial size is known. Check them out! http://www.cplusplus.com/reference/stl/vector/

Sunday, March 4, 2012

The Orthodox Canonical Class Form

Every "good" programmer has heard it and knows it: the canonical class form, the "must-haves", the four methods every class needs to possess a certain degree of thoroughness in acting out its purpose. In case you have forgotten, I will go ahead and relist them again here:

1. Default Constructor
2. Copy Constructor
3. Assignment Operator
4. Destructor

While this explanation will be stated according to Timothy Budd's Introduction to Object-Oriented Programming book, I believe he does a great job of outlining each of these methods and iterating their purpose to the reader. The default constructor is used to initialize objects and data members when no other value is readily available. There is of course in most cases a default constructor, but relying on the default constructor is typically not a smart choice. The copy instructor is used in the implementation of call-by-value parameters. The assignment operator is rhetorical, and the destructor is invoked when an object is deleted. The copy constructor, to me, seems to always be the least necessary. How often do I actually need to copy an object when I already have access to the original? I typically pass objects as pointers, but I can see how working with others and failing to write a copy constructor could cause somebody to shoot themselves in the foot when passing values by value.
I am sure most readers have these four functions hardwired into their brains, but it is always good to reiterate! I personally fail to always take care of these things, and my goal is that this post will remind me to think through what I am doing and about the issues that can arise when the canonical class form is discarded. I would enjoy hearing some other purposes for the canonical class methods in the comments below!