LinuxDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


C++ Memory Management: From Fear to Triumph, Part 3
Pages: 1, 2, 3, 4

Example 7. Handling memory via pointers: output

Deleting Derived Data, Deleting Base Data

The auto_ptr behaves like an ordinary pointer in many respects. When an auto_ptr goes out of scope, however, it automatically deletes the memory that it is holding — something that the ordinary pointer does not do.

In addition to memory leaks, the auto_ptr also prevents dangling references. When you assign one auto_ptr to another, the auto_ptr on the right hand side actually becomes the equivalent of a NULL pointer! The target of the assignment (on the left hand side) now points to the memory that the right hand side auto_ptr pointed to before. This is a powerful example of how the semantics of an operation (in this case assignment) can be defined in C++.

Recall our discussion in the second article about consistency of ownership. The auto_ptr maintains such consistency. First, it owns the memory that it points to. Second, the semantics of assignment for auto_ptrs is transfer of ownership. The target of the assignment becomes the new owner of the memory, while the source turns into a NULL pointer, which owns nothing. The two diagrams below contrast the assignment semantics of ordinary pointers with those of the auto_ptr.

Block Diagram
Figure 1. Assignment semantics of ordinary pointers

Block Diagram
Figure 2. Assignment semantics of the auto_ptr

The auto_ptr is a very simple smart pointer, but it has many uses (see the article Using auto_ptr Effectively, for example). Its copy semantics, however, make it unsuitable for some operations. Most notably, the auto_ptr cannot be used in STL containers (the STL is part of the C++ standard library, and is discussed next in this article). It is not necessary, however, to restrict yourself to just one kind of smart pointer. Boost.org, for example, provides free implementations of several smart pointers. Their shared_ptr is based on reference counting (an elegant, efficient memory management technique that can provide similar benefits to garbage collection) and is safe to use in containers.

The smart pointer is a powerful idea for writing better C++ programs. The standard auto_ptr, the offerings at Boost.org, and many other implementations provide you with lots of choices for various tasks. Using them as examples, you might even write smart pointer classes yourself with appropriately fine-tuned semantics for your application.

Be Aware of C++ Alternatives to Traditional C Methods

Because C++ is largely compatible with C, it is much easier to port C code into a C++ environment. It does not mean, however, that you should program in C++ as you would in C. In fact, the C++ standard library provides safe, simple solutions to many problems that are very troublesome in C.

For example, arrays and strings are two problematic issues that the C++ standard library solves very well. Here are two programs to illustrate this point. The first is written in the traditional C style, while the other one uses the new features of the C++ standard library.

Example 8. Array of strings, C style

//*** C STYLE ARRAY OF STRINGS *** 

#include <stdio.h>

void print_strings(char** strings, unsigned num) {
  
  for (int i = 0; i < num; ++i) {
    printf("%s\n",strings[i]);
  }
}

int main() {

  char* strings[3] = {"One", "Two", "Three"};

  print_strings(strings, 3);
}

//*** END: C STYLE ARRAY OF STRINGS ***

Example 9. Array of strings, C++ style

//*** C++ STYLE ARRAY OF STRINGS *** 

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void print_strings(const vector<string>& strings) {
  
  for (int i=0; i < strings.size(); ++i) {
    cout << strings[i] << endl;
  } 
}

int main() {

  vector<string> strings(3);
  strings[0] = "One"; strings[1] = "Two"; strings[2] = "Three";
  
  print_strings(strings);
}

//*** END: C++ STYLE ARRAY OF STRINGS ***

Both examples produce the same output.

Example 10. Array of strings: output

One
Two
Three

The second example uses the string class from the standard C++ library. It also uses the vector template class, which implements a resizable array. The vector template is part of the Standard Template Library (STL), a powerful, elegant, and highly extensible set of algorithms and data structures. (STL data structures such as vector are generally referred to as containers because they are designed to hold other objects). The STL is included in the C++ standard library. Performance of the first and second example is similar, except in the initial step, where filling the vector with string objects is significantly slower. In many real-world situations, the initialization penalty for the C++ style solution would be much smaller.

At first glance, the C++ example is more complex, but not overly so. Its increased safety, however, is already apparent; vector knows its own size. Thus, misstating the length of the array when calling print_string — a disastrous error in the C style version — is entirely avoided.

There's a lot more here that meets the eye, however. The true difference between the C and C++ versions is in responsibility for memory management. In the C++ example, vector and string handle their own memory. Each string, for instance, will automatically clean up its character buffer when the vector is destroyed, even if all of the objects were dynamically allocated. If the strings in the C example were dynamically allocated, however, it would be necessary to provide extra code to delete them. As a small illustration of the capabilities of the C++ programming style, here is a slightly modified version of the array of strings example.

Example 11. Array of strings, C++ style (version 2)

//*** C++ STYLE ARRAY OF STRINGS (VERSION 2) *** 

#include <iostream>
#include <string>
#include <vector>
using namespace std;

void print_strings(const vector<string>& strings) {
  
  for (int i=0; i < strings.size(); ++i) {
    cout << strings[i] << endl;
  } 
}

int main() {
  vector<string> strings(3);
  strings[0] = "One"; strings[1] = "Two"; strings[2] = "Three";
  
  print_strings(strings);

  strings[0] += " and a";
  strings[1] += " and a";

  strings.resize(4);
  strings[3] = "and One, Two, Three!";

  cout << endl << "Encore!" << endl << endl;
  print_strings(strings);
}

//*** END: C++ STYLE ARRAY OF STRINGS (VERSION 2) ***

Here is the output.

Example 12. Array of strings (version 2): output

One
Two
Three

Encore!

One and a
Two and a
Three
and One, Two, Three!

The examples shown here should give you an understanding of how C++ features can be applied to traditional C problems. Many variations are possible. For example, a Boost.org shared_ptr (covered previously) could be used with vector. This would keep the automated resource management, while allowing the vector to effectively contain objects belonging to an inheritance hierarchy (note that you should never use the standard auto_ptr inside vector or other STL containers).

Doing things the C way still has its place. Working with legacy code, developing kernel-level software, or creating an embedded system often requires the older C style. Many decades and many platforms later, C is nowhere near obsolete. Nevertheless, the C++ alternatives are often the better choice, particularly for user-level code. In general C++ development, it is a good rule of thumb to favor the C++ solutions over traditional C approaches, resorting to the latter only when it is clearly necessary.

Pages: 1, 2, 3, 4

Next Pagearrow




Linux Online Certification

Linux/Unix System Administration Certificate Series
Linux/Unix System Administration Certificate Series — This course series targets both beginning and intermediate Linux/Unix users who want to acquire advanced system administration skills, and to back those skills up with a Certificate from the University of Illinois Office of Continuing Education.

Enroll today!


Linux Resources
  • Linux Online
  • The Linux FAQ
  • linux.java.net
  • Linux Kernel Archives
  • Kernel Traffic
  • DistroWatch.com


  • Sponsored by: