12

3.10/10 says:

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

However, the term "access" is not defined anywhere. In this context does it mean read, or read or modify ?


In the C standard it is unambiguously defined as read or modify. However in C++11 it seems to be used with different meanings at different times, for example:

1.9/8:

Access to volatile objects are evaluated strictly according to the rules of the abstract machine.

Clearly this is meant to be read or modify, however in many other places such as 1.10/24:

  • access or modify a volatile object, or

it is used as if it only means read.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    You could shorten the title to: "In C++, what does 'access' mean?" This is a great question. (Of course, regarding the strict aliasing rule specifically, the intent is surely "read or modify", similar to C.) – Nemo Mar 12 '15 at 03:39
  • @Nemo Agree, although I am most interested in this particular case. That could be a separate question perhaps. – M.M Mar 12 '15 at 03:48
  • Well, regardless of their intent in this section, they have certainly not stated it clearly, so I would say you have definitely found a bug in the spec. – Nemo Mar 12 '15 at 03:52
  • The standard is notoriously bad at this sort of thing. Even a rabid language lawyer like myself avoids such questions like the plague. You're on your own ;) – Lightness Races in Orbit Mar 12 '15 at 04:32
  • @LightnessRacesinOrbit heh. Strict aliasing problems are horrible enough to unwind without this ambiguity thrown into the mix. I'd always assumed it should be as in C; but I've been reading a few other answers on strict aliasing (particularly relating to combining with placement new) and they all tacitly rely on *access* only meaning *read*, so I was hoping to clear this up before commenting/posting further on strict aliasing – M.M Mar 12 '15 at 04:37
  • Placement new is a little odd - it reuses the storage, which ends the lifetime of the object that's been there before. – T.C. Mar 12 '15 at 04:44

2 Answers2

4

It must mean both read and write, or the rule wouldn't mean much. Consider the example from http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html:

float *P;
void zero_array() {
   int i;
   for (i = 0; i < 10000; ++i)
       P[i] = 0.0f;
}

The example code above can be optimized into a memset only if the compiler can assume that none of P[i] aliases P. But consider a world in which only reading from an disallowed glvalue is UB, then the above code would not invoke UB even if P[i] aliases P for some i - e.g., if someone did P = (float *) &P;, because all reads of P are perfectly legal - they all use the lvalue expression P.


Edit: CWG issue 1531 is directly on point. The issue was moved to DR (defect report) status in April 2013, but the resolution, for whatever reason, wasn't applied to the working paper.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • Great example (as is your example in the other comment) – M.M Mar 12 '15 at 05:01
  • I would see no difficulty with the Standard specifying that cross-type reads of a PODS yield potentially-Indeterminate Value, and cross-type writes of a PODS set it to potentially-Intermediate Value, at least if the Standard were clearer about what can and cannot happen when working with Intermediate Values of types which have no natural trap representations (a point the Standard should address anyway, IMHO). – supercat Jun 29 '16 at 17:12
2

I don't claim to be a language lawyer. However...

I would interpret the phrase "access the stored value of an object" as "read the stored value of an object".

That interpretation makes more sense given the previous paragraph, which talks about modifying an object.

9 If an expression can be used to modify the object to which it refers, the expression is called modifiable. A program that attempts to modify an object through a nonmodifiable lvalue or rvalue expression is ill-formed.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • 1
    By this reading, stuff like `int a = 0; *((short *) &a) = 100; std::cout << a;` doesn't break strict aliasing. That makes little sense. – T.C. Mar 12 '15 at 04:35
  • @T.C. I see what you mean. Is there anything in the standard where `read` is more restrictive than `write`? – R Sahu Mar 12 '15 at 05:15