Feeds

Variables Won't Constants Aren't:

A random walk through constant values in C++

Combat fraud and increase customer satisfaction

I first read the lament to the capricity of programming in the title of this piece in Creative Computing, years before C was devised. But it’s still true that there is no way, not even one, of being absolutely sure that a value you set in C or C++ won’t change.

This is despite the fact that in the 30 years following the creation of C, C and C++ have acquired new keywords, features and libraries and have been generally enhanced to a point where my ancient battered copy of Kernighan and Richie hides in a cupboard and refuses to even sit on the desk where Visual C++ 2005 lives.

C++ gives the programmer a menu of methods to help him/her protect his/her data. At least, that’s what’s implied if you don’t read Stroustrup too closely. It’s not that you’re being lied to; it’s just that someone is being rather economical with the truth.

It’s tempting to think that, given:

const int MyConst = 42;
double MyVals[MyConst];
for (int i=0; i != MyConst; i++) {
    // ...
}

you won’t ever go off the end of the array. Tempting, but wrong; and it is quite trivial to make it happen:

int& x = (int&) MyConst;
x = 43;

The default in C++ is variables, not constants; and thus you probably won’t even get a warning if you do such a thing. And so you implicitly, but silently, cast away constness.

This is one of the many reasons that classical C style casts are frowned upon in most coding standards. But for most programmers these days, the only time that they ever review someone else’s code is at interview [and not always then – Ed] - so probably no-one will notice if they aren’t following standards.

The accepted, but still rather worrying, technique is:

int& CPlusCast = const_cast<int&>(MyConst);

[Am I the only one who thinks this cast has the wrong name? – Dominic]

OK, but when you’re hunting a bug, then you might well be tempted to think that this means that MyConst can’t change. Yet it might or might not mean that; and of course now that constness is gone, MyConst can be passed into a function with a variable parameter signature.

Even specifying:

void Increment(const int& x)

doesn’t mean it won’t ever change - as we’ve seen. More than that, since threads are coming back into mainstream programming, your MyConst value may change randomly at some random point during execution.

You can always try to specify that a function mustn’t change any class variables, which would be really handy if your class is supposed to be inherited from, but again, this can be changed later.

Const functions only protect members of the class, and the language also stops you getting around this by getting the const function to call a non-const member. But the syntactic protection does not extend to globals; although if you use them you’re not really into this level of discipline anyway.

And it just wouldn’t be C++ if there weren’t yet another workaround available. So, we can specify member variables as mutable, and thus make them prey to random change by the sort of people who think “const member function” actually means that only externally observable states should remain constant; and that the function should be free to meddle with its private housekeeping variables.

But sometimes you need to expose some internal structure like the STL string or MFC CString, so that you can use the character buffer with older code. STL does the right, but fallible, thing and so the c_str() member returns a const pointer; which at least takes some effort if you’re determined to corrupt it. MFC doesn’t even try.

STL also has const_iterators, which of course aren’t constant (because there wouldn’t be much point having an index that didn’t change); but the idiom is that you can’t directly change the values of the collection, which is both safer and potentially rather faster. An iterator that you know won’t change things can not only be cached, but is also rather easier to multithread.

Now, so far I’ve only complained about intentional changes to variables. We also have to live with the possibility of memory being trashed, since const is just a syntactic sugar coating for the bitter reality of the underlying memory model. Hence, in Visual C++ 2005, I can illustrate a simplified example of a const value being trampled on simply for being too close to another on the stack:

void HeisenBug(void) {
    char a = 42;
    char Bug[5];
    strcpy(Bug, "123456789abcdefghijk");
}

Note that this mucks up the value “before” the Bug array; and that this is compiler-dependent. This effect may be anything from benign to subtly malicious.

Of course, if you’re in the IDE of a decent debugger like Visual Studio 2005, then this effect will be caught; but if you’re in production code, you simply get a silent change of the value. The debug code will contain traps for this, but these disappear in release; and of course optimised code is the most vulnerable. Live fast die young. And so we get a “Heisenbug”, an error that changes when you try to observe it in the debugger. This could still happen if the “constant” string was #defined, because the value has to be somewhere, even if the compiler has folded long strings.

Now, modern operating systems allow you to write-protect blocks of memory; but that is both non-portable and deeply ugly - and you’ve probably worked out for yourself that it can be turned off by the same API. In older compilers, it is also entirely possible for explicit constants to be changed; and Microsoft actually used to advise developers to write code such as:

char* Fname = " ImpliedVol"; // Note the space at the start of the name
Fname[0] = (BYTE) strlen(Fname);

to cope with BASIC-style APIs that required the length of the string to be in the first byte. It worked - yes, really; a large percentage of the world’s derivative pricing makes its way into dealing systems that way - but Microsoft now makes all literal strings read only, which is more elegant. Although it does mean that, a whole pile of its example code now won’t work anymore.

And, of course, any memory value can be hit by a stray pointer.

However, it’s not all bad as const can also be a big hint to the compiler to make better code. If you have a big vector of some class, then default pass by value means that a simple utility algorithm like:

template <typename T> double Sum(vector<T> vec)

may end up calling the constructor many times. As it happens, STL is smart enough to keep this to a minimum; but if we write:

template <typename T> double Sum(const vector<T>& vec)

then we are telling the compiler quite explicitly that vec is basically just an alias to the variable in the calling function; and then it’s much easier for the compiler to generate direct inline access. Thus, const references can make your code both faster and more robust.

So, to summarise, C++ does do constants, and often they are useful, but they are never completely trustworthy. ®

Combat fraud and increase customer satisfaction

More from The Register

next story
Ubuntu 14.04 LTS: Great changes, but sssh don't mention the...
Why HELLO Amazon! You weren't here last time
This time it's 'Personal': new Office 365 sub covers just two devices
Redmond also brings Office into Google's back yard
Next Windows obsolescence panic is 450 days from … NOW!
The clock is ticking louder for Windows Server 2003 R2 users
Half of Twitter's 'active users' are SILENT STALKERS
Nearly 50% have NEVER tweeted a word
OpenBSD founder wants to bin buggy OpenSSL library, launches fork
One Heartbleed vuln was too many for Theo de Raadt
Microsoft TIER SMEAR changes app prices whether devs ask or not
Some go up, some go down, Redmond goes silent
Batten down the hatches, Ubuntu 14.04 LTS due in TWO DAYS
Admins dab straining server brows in advance of Trusty Tahr's long-term support landing
Red Hat to ship RHEL 7 release candidate with a taste of container tech
Grab 'near-final' version of next Enterprise Linux next week
Windows 8.1, which you probably haven't upgraded to yet, ALREADY OBSOLETE
Pre-Update versions of new Windows version will no longer support patches
prev story

Whitepapers

Mobile application security study
Download this report to see the alarming realities regarding the sheer number of applications vulnerable to attack, as well as the most common and easily addressable vulnerability errors.
3 Big data security analytics techniques
Applying these Big Data security analytics techniques can help you make your business safer by detecting attacks early, before significant damage is done.
The benefits of software based PBX
Why you should break free from your proprietary PBX and how to leverage your existing server hardware.
Securing web applications made simple and scalable
In this whitepaper learn how automated security testing can provide a simple and scalable way to protect your web applications.
Combat fraud and increase customer satisfaction
Based on their experience using HP ArcSight Enterprise Security Manager for IT security operations, Finansbank moved to HP ArcSight ESM for fraud management.