Feeds

Variables Won't Constants Aren't:

A random walk through constant values in C++

Choosing a cloud hosting partner with confidence

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. ®

Business security measures using SSL

More from The Register

next story
'Windows 9' LEAK: Microsoft's playing catchup with Linux
Multiple desktops and live tiles in restored Start button star in new vids
Not appy with your Chromebook? Well now it can run Android apps
Google offers beta of tricky OS-inside-OS tech
New 'Cosmos' browser surfs the net by TXT alone
No data plan? No WiFi? No worries ... except sluggish download speed
SUSE Linux owner Attachmate gobbled by Micro Focus for $2.3bn
Merger will lead to mainframe and COBOL powerhouse
iOS 8 release: WebGL now runs everywhere. Hurrah for 3D graphics!
HTML 5's pretty neat ... when your browser supports it
Greater dev access to iOS 8 will put us AT RISK from HACKERS
Knocking holes in Apple's walled garden could backfire, says securo-chap
NHS grows a NoSQL backbone and rips out its Oracle Spine
Open source? In the government? Ha ha! What, wait ...?
Google extends app refund window to two hours
You now have 120 minutes to finish that game instead of 15
Intel: Hey, enterprises, drop everything and DO HADOOP
Big Data analytics projected to run on more servers than any other app
prev story

Whitepapers

Providing a secure and efficient Helpdesk
A single remote control platform for user support is be key to providing an efficient helpdesk. Retain full control over the way in which screen and keystroke data is transmitted.
Saudi Petroleum chooses Tegile storage solution
A storage solution that addresses company growth and performance for business-critical applications of caseware archive and search along with other key operational systems.
Security and trust: The backbone of doing business over the internet
Explores the current state of website security and the contributions Symantec is making to help organizations protect critical data and build trust with customers.
Reg Reader Research: SaaS based Email and Office Productivity Tools
Read this Reg reader report which provides advice and guidance for SMBs towards the use of SaaS based email and Office productivity tools.
Security for virtualized datacentres
Legacy security solutions are inefficient due to the architectural differences between physical and virtual environments.