Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

The Problem with const Data Members


March 1997/The Problem with const Data Members

Adding const qualifiers to objects that should not be modified is almost always a good idea. Almost.


C++ allows classes to define constant non-static data members, which seems a handy enough feature at first glance. If you are thinking of using constant non-static data members in your next design, this article may help you figure out if it's really a good idea. As I have found, sometimes it isn't.

Consider a class designed to store information about employees. This class might contain fields that are conceptually constant — for example, date of birth. At first it seems logical to make this field constant in a C++ class Employee:

class Employee{
   public :
     Employee(const string &n,
              const unsigned long &d):
                 name(n), dob(d){}
     // possible other members
  private :
    string name;
    const unsigned long dob;
    // possible other data members
}

This class has a few limitations. First, although the compiler can generate a correctly-working copy constructor (which I neglected to define), it cannot generate an assignment operator. If a program creates two Employee objects e1 and e2, the statement e1 = e2 will cause a compiler diagnostic. This assignment is invalid because it implicitly attempts to change the value of the const member e1.dob. The Watcom 10.5, Borland 4.5 and Microsoft 4.0 [1]

compilers all generate an error when such an assignment is attempted.

Another limitation is that it is difficult to provide a useful default constructor for this class. A default constructor is essential if you want to create, say, arrays of Employee objects. Defining a default constructor is a little bit tricky; the main thing to remember is that const non-static data members get initialized in the constructor's initialization list — and you must initialize all of them. The default constructor must set the dob field to some value, and this value cannot be subsequently altered. So the constructed array will be practically useless.

Given the questionable benefit of having a default constructor, the class designer may elect not to define one. But this class also lacks an assignment operator, and the limitations of this class are quite severe. The user program cannot create heap-based arrays of the class's objects, nor can it use procedures that need to create temporary objects.

One solution is to create a special-purpose assignment operator. To compile without diagnostics, such an assignment operator must follow one of two approaches: 1) avoid attempting to modify the contents of any const data members 2) "cast away const" on the const data members before modifying them.

The first approach solves none of the problems mentioned above, so I do not consider it further. The second approach may be implemented as follows:

Employee& Employee::operator=(
    const Employee &op2){
    if(&op2 != this){
      name = op2.name;
      //cast away constantness in
      // order to assign dob
      (unsigned long&)dob = op2.dob;
    }
    return *this;
}

Class Employee now has a copy constructor, an assignment operator, and a default constructor, which will perform as expected.

Evaluation

At this point it's a good idea to reexamine the wisdom of making Employee::dob a constant in the first place. Note that dob is already defined as private, so making it const is unnecessary to protect it from modification by users. dob's constness is necessary only to protect it from code internal to the Employee class or from friends of Employee. These entities can still modify the field by casting away constness, just as the assignment operator did, so the safety afforded is not absolute. Is the modicum of safety achieved worth it? As the class stands, I think not, but if the class were very complex and contained many member functions perhaps it would be worth the effort.

In conclusion, constant non-static data fields create complications, and in most cases it is better not to design such fields into a class. The designer can adequately protect these fields from undesired write access by making them private. In cases where the class is very large and complex you might consider making certain fields constant and coding an assignment operator which casts away constness. In rare cases you might even want the limitations of a class that has constant non static data and no assignment operator or default constructor. If you need to go this far you may also need to suppress a compiler generated copy constructor by supplying the class with a private, non-defined copy constructor.

Acknowledgement

[1] Thanks to Art Doglione of Scottsdale, Az for testing this on the Microsoft compiler.

Jack Hawes has a degree in mathematics from Arizona State University. He has been programming for 12 years. He may be reached at [email protected].


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.