-4

In C, the following code is valid, but in C++ it requires you to initialize it.

const size_t s;

In C, you have to strip away the constness and then later initialize it, but it isn't guaranteed to work. However, if they allow this feature to exist, then they must've had a good reason. So why did this change in C++?

  • 6
    Why would you want an uninitialized `const` variable? So the value is unspecified at runtime, and you can't change it? That sounds like a terrible idea. – Cory Kramer Sep 15 '14 at 13:24
  • @CYber https://en.wikipedia.org/wiki/Const-correctness#Loopholes_to_const-correctness – user4042737 Sep 15 '14 at 13:26
  • 3
    "However, if they allow this feature to exist, then they must've had a good reason": That's not always the case in C or C++, so don't get too caught up thinking that. – Cornstalks Sep 15 '14 at 13:29
  • 1
    like I said they allow this in C... so if your answer is "why would you want to do that"..that doesn't really answer my question. – user4042737 Sep 15 '14 at 13:30
  • Because trying to change a variable by casting away constness has undefined behaviour so it is not allowed. In C, const variable always gets some memory. In C++, it may or may not. – Mohit Jain Sep 15 '14 at 13:30
  • From the wikipedia page you just linked to: "There are several loopholes to pure const-correctness in C and C++. They exist primarily for compatibility with existing code." – dohashi Sep 15 '14 at 13:30
  • @mohit that sounds like a real answer... – user4042737 Sep 15 '14 at 13:31
  • @user4042737: I'm not trying to answer the original question; I'm trying to warn you that your premise is flawed. – Cornstalks Sep 15 '14 at 13:31
  • @MohitJain In C++, a `const` variable may be part of an integral constant expression; in C no. Otherwise, they're identical. – James Kanze Sep 15 '14 at 13:31
  • Did your compiler issue you any warnings? (Did you turn warnings level up?) – Thomas Matthews Sep 15 '14 at 15:26
  • @JamesKanze Thanks. I had a perception that C++ compilers are more aggressive at const optimization majorly because (as you say) it can be used as a part of integral constant. – Mohit Jain Sep 16 '14 at 05:19
  • @MohitJain They may be, although in most cases, I would expect the optimization components to be the same for both C and C++. – James Kanze Sep 16 '14 at 09:35

3 Answers3

6

In C the const keyword is not a real const. That's why you use the preprocesser to create real const values.

#define CONST_PREPROCESSOR 5
const int const_keyword = 5;

int myarray[CONST_PREPROCESSOR]; // valid
int myarray[const_keyword]; // compile error in C - valid in C++

In C++ the const keyword has been improved and you can declare real const values. That's why it has to be initialized before compiling the code.

code monkey
  • 2,094
  • 3
  • 23
  • 26
  • 3
    The rule is slightly different: to be used in an integral constant expression, the initialization must be visible to the compiler. But you can still write something like `extern const int i;` in C++. – James Kanze Sep 15 '14 at 13:35
2

No reason, really. C++ favored safety, C orthogonality. But there's nothing you can legally do with an uninitialized const variable in C except take its address; any attempt to modify it or to read it is undefined behavior.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Is it undefined *behavior* to read *any* uninitialized variable? What about those that don't have a trap representation (like `unsigned`)? – Cornstalks Sep 15 '14 at 13:35
  • 1
    @Cornstalks There's a special exception for character types, but otherwise, reading an uninitialized variable is undefined behavior (and `unsigned` can have a trap representation). – James Kanze Sep 15 '14 at 13:42
  • `unsigned` can have a trap representation? Wow. I guess I've got some reading to do. – Cornstalks Sep 15 '14 at 13:44
  • @Cornstalks: Some compilers (e.g. Gcc and Clang) reorder statements based on the assumption that no read will occur before the first write. See for example http://stackoverflow.com/questions/25074180/is-aa-or-a-a-undefined-behaviour-if-a-is-not-initialized – mafso Sep 15 '14 at 13:45
  • @mafso Yes. The issue of a possible trap representation is a red herring. Accessing an uninitialized variable is undefined behavior, and a compiler is free to assume that it doesn't happen. – James Kanze Sep 15 '14 at 15:26
  • @JamesKanze, for C your first statement is just wrong, C distinguishes between indeterminate and unspecified values and then UB. These are three different things. No, reading an unitialized variable is by itself not UB. – Jens Gustedt Sep 15 '14 at 16:17
  • @JensGustedt So what are the requirements concerning its behavior? §6.2.6.1 seems clear enough; uninitialized objects have an indeterminate value representation, and if the stored value of such an object is read, it is undefined behavior. – James Kanze Sep 15 '14 at 16:50
  • @JamesKanze, indeterminate can mean that it is either an unspecified value (AKA random data) or a trap representation. Accessign it is only UB if the value is a trap. For types that don't have traps (allmost all types on almost all systems) it is just unspecified. The other possibility to have UB is if the "variable could have been declared as `register`", that is its address is never taken. So on a "normal" modern architecture reading an uninitialized variable that is backed in memory "just" gives random data. – Jens Gustedt Sep 16 '14 at 07:02
  • @JensGustedt Your argument is circular. The C standard defines trap representation to be anything (and doesn't require it to be specified). And you still fail to meet the other criterion: if the behavior isn't undefined, where in the standard is it defined. (FWIW: accessing an uninitialized variable has always been considered undefined behavior, since the very first C standard, by the members of the committee.) – James Kanze Sep 16 '14 at 09:38
  • @JamesKanze, I don't see where it is circular. There is a clear definition of trap representation: a trap representation is a bit pattern that doesn't correspond to a value of the type. Most modern architectures don't have that, all bit patterns correspond to valid values. And no, it has not "always" been considered UB, I don't see where you get that from. There is an ongoing discussion in the C standards committee of what to expect from unspecified values, in particular if they can be considered stable or not. So *using* such a value may then lead to UB, but that is a different thing. – Jens Gustedt Sep 16 '14 at 09:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/61330/discussion-between-james-kanze-and-jens-gustedt). – James Kanze Sep 16 '14 at 10:11
  • @JensGustedt I'm not familiar with what is going on in the C committee today; I was involved in the early days, and had many discussions with the committee members; there was never any doubt in anyone's mind that accessing an uninitialized value was undefined behavior. – James Kanze Sep 16 '14 at 10:13
  • @JensGustedt FWIW: although not normative, the text in §6.5.2/16 ends with "p would have an indeterminate value, which would result in undefined behavior." Which makes it clear that the authors of the C standard considered accessing an uninitialized variable undefined behavior. – James Kanze Sep 16 '14 at 10:36
1

In C, you have to strip away the constness and then later initialize it, but it isn't guaranteed to work.

This is undefined behavior, so anything can happen, including the program crashing.

However, if they allow this feature to exist, then they must've had a good reason

You are incorrectly assuming that there is sane rationale behind everything in the C language. More likely, const size_t s; is allowed just because the syntax happened to be specified like that - it doesn't treat the const type qualifier any different than the other type qualifiers (such as volatile).

So why did this change in C++?

Probably because it doesn't make any sense to declare an uninitialized constant.

Lundin
  • 195,001
  • 40
  • 254
  • 396