1

With reference to the discussion here

$3.7.1/2 - "If an object of static storage duration has initialization or a destructor with side effects, it shall not be eliminated even if it appears to be unused, except that a class object or its copy may be eliminated as specified in 12.8."

$12.8/15- "When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects."

Is the above case, specific examples of a case, where even a volatile read/write may also be optimized away (e.g. if a copy constructor has a read/write to a volatile variable).

So the question is "can a copy constructor be elided even if the copy constructor has a read/write of a volatile variable?"

Community
  • 1
  • 1
Chubsdad
  • 24,777
  • 4
  • 73
  • 129
  • @Billy ONeal: can a copy constructor be elided even if the copy constructor has a read/write of a volatile variable? – Chubsdad Aug 31 '10 at 03:01
  • @chubsdad: Yes, it can. Volatile members of a class don't make any sense anyway. `volatile` is for hardware memory access. It should not ever be used for anything else. Ever. Period. It is not a multi threading tool like it is in Java and C#. – Billy ONeal Aug 31 '10 at 03:04
  • @Billy ONeal: I didn't necessarily mean volatile class member variable. Let's hypothetically take the example of a copy constructor updating a namespace scope volatile variable! – Chubsdad Aug 31 '10 at 03:06
  • @chubsdad: Namespace scoped volatile variables don't make sense either. About the only place they make sense is for globals, and even then it's entirely platform dependent, and even then only for places where you're writing things like device drivers interfacing to devices which use memory mapping. – Billy ONeal Aug 31 '10 at 03:09
  • @Billy: Globals are at namespace scope. Its just the global namespace scope. – Dennis Zickefoose Aug 31 '10 at 03:46
  • @Dennis: Err... no they are not. Globals have a standard ABI and can be accessed from C. The minute you add C++ concepts any form of ABI comparability -- even between separately compiled versions of the same code -- goes out the window. Hence you would not be able map `volatile` to any form of hardware fixed memory address, and therefore lose the only point of `volatile` in the first place. – Billy ONeal Aug 31 '10 at 03:55
  • And in a purely abstract, theoretical sense, I could see volatile members within a class having meaning. You might have several pieces of hardware all mapped to your memory, and each instance of your class represents one. – Dennis Zickefoose Aug 31 '10 at 03:57
  • 3.3.5.3: The outermost declarative region of a translation unit is also a namespace, called the global namespace. A name declared in the global namespace has global namespace scope (also called global scope). The potential scope of such a name begins at its point of declaration (3.3.1) and ends at the end of the translation unit that is its declarative region. Names with global namespace scope are said to be global. – Dennis Zickefoose Aug 31 '10 at 03:58
  • @Dennis: Yes, that is there so that when the standard says "A namespace", it's clear that things in the "global namespace" apply. But in terms of ABI, the global namespace isn't a namespace at all, because it doesn't require that names be decorated. – Billy ONeal Aug 31 '10 at 04:04
  • @Billy: You can have pointers to volatile, just like you can have pointers to const. Such pointers can be anywhere you want. So all this talk about ABIs [assuming your compiler respects a particular ABI... it doesn't have to, you know] is pretty much irrelevant. – Dennis Zickefoose Aug 31 '10 at 04:26
  • @Billy ONeal: 1) volatile is not just for hardware locations (it is used as a memory barrier (A memory location can be updated from an autonomous thread of control and thus required volatile protection)). 2) Globals are in the global namespace in C++. 3) I don't see how ABI maps to these discussion (What you say is true but not relevant) stop muddying the water with irrelevant details. – Martin York Aug 31 '10 at 08:34
  • @Martin York: No, that is the confusion here -- it need not be used as a memory barrier. It does not require accessing the variable via a memory barrier, and nothing stops another CPU or anything else on the system from modifying it behind your back as you try to read it. Any type of memory barrier is going to be platform specific. – Billy ONeal Aug 31 '10 at 13:09
  • @Billy ONeal: Your sentence is rambling and I don't seem able to see your point. – Martin York Aug 31 '10 at 16:45

2 Answers2

0

NRVO is only allowed if the named object is non-volatile [its right in the same section you quoted, the first bullet], but otherwise I don't see why not. After all, if the object you are creating is volatile, you are still writing to it, you just aren't doing so via the copy constructor. And it doesn't qualify which side effects it is allowed to ignore, so clearly if the volatile read/write is within the copy constructor itself the compiler doesn't have to care.

Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38
  • I meant a case where the class object is non cv-qualified, but the copy constructor does a read/write to global/namespace scope volatile variable. In this case, is the compiler is allowed to elide away the copy constructor as the Standard says. But why? Why is the side effect of copy constructor (updating the volatile variable e.g.) not a deterrant for eliding away the copy constructor? – Chubsdad Aug 31 '10 at 04:10
  • @chubs: Because side effects are never deterrents for eliding copy constructors. The compiler often doesn't even know what side effects there might be when it decides to elide the copy, so in general it can't take this information into account. – Dennis Zickefoose Aug 31 '10 at 04:19
0

Sometimes. Funny you should ask, since something I mis-remembered about volatile (which Johannes called out) led me to look up exactly such trivia.

§12.8/15:

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the function return type, the copy operation can be omitted by constructing the automatic object directly into the function’s return value

So, it's OK to eliminate a volatile access by eliding the constructor, but not if the entire object is volatile.

Also, it can make a difference if a function returns volatile foo by value as opposed to plain foo, because construction of the volatile temporary cannot be elided!

foo factory_a(); // return class by value
const foo factory_b(); // also return by value: rather pointless
volatile foo factory_c(); // implies no elision

Note that the cv-qualification of the returned temporary also affects access semantics of the temporary, for example factory_b().non_const_method() is illegal. So this is all more arcane than boneheaded.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421