1

How to avoid writing the same body (bar++;) for volatile and non-volatile foo methods in the next example?

#include <iostream>

struct A { 
    int bar = 0;
    void foo() { bar++; } 
    void foo() volatile { bar++; } 
};

int main() {
    A a;
    a.foo();

    volatile A va; 
    va.foo();
}

This question is a complete analog of How do I remove code duplication between similar const and non-const member functions?, but since const and non-const versions don't affect compiler optimizations, I am wondering: if apply the same answer for volatile, wouldn't it be inefficient for non-volatile uses because volatile can make code slower?

2 Answers2

1

if apply the same answer for volatile, wouldn't it be inefficient for non-volatile uses because volatile can make code slower?

Yes.

How to avoid writing the same body (bar++;) for volatile and non-volatile foo methods in the next example?

As far as I can tell, the only option with a non-static member function is to put the function body into a function-like macro.

It might be preferable to use a non-member (or static member) function template instead:

template<class AA>
void foo(AA& a) { a.bar++; }

This requires no repetition and can be invoked with either volatile or non-volatile object.

eerorika
  • 181,943
  • 10
  • 144
  • 256
  • Great idea! Probably the template method is the best that is possible to achieve. –  Jan 05 '20 at 22:10
0

Since volatile method can be called for none volatile objects simply trash none volatile method.

Anyway volatile has little usage see this topic, so do not make your code to complex and do not use this keyword if you do not have a really good reason to do it.

Marek R
  • 23,155
  • 5
  • 37
  • 107
  • 1
    If you only keep the volatile method, it will be more inefficient. The question is about whether you can avoid the inefficiency and also avoid repeating code. – G. Sliepen Jan 05 '20 at 20:26
  • 1
    IMO you should not use `volatile` at all. [See this](https://stackoverflow.com/a/4558031/1387438). – Marek R Jan 05 '20 at 20:27
  • @MarekR Unfortunately, I really have to use it (for CUDA managed memory access synchronization). –  Jan 05 '20 at 20:29
  • @BhavinChirag I don't know about CUDA, though in C++, volatile ain't used for memory access synchronization, std::atomic is – JVApen Jan 05 '20 at 20:46
  • @JVApen CUDA programming guide mentions that the use of volatile is a correct and necessary thing to do here https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#memory-fence-functions and here https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#volatile-qualifier –  Jan 05 '20 at 20:49
  • @BhavinChirag I'm probably missing something here, but... can you clarify the context in which the volatile qualifier is being used in the references you link to? At first glance it would appear to relate to the code running on the GPU/CUDA device and not the host. – G.M. Jan 05 '20 at 21:40
  • @G.M. Yes, it is about the code, that runs on GPU. Follow the first link that I provided above, read the paragraph under `void __threadfence();`. In short, it says that you have to use volatile to bypass the cache. It differs from x86 arch: you don't have to use volatile, because gcc `__sync_synchronize` guarantees that memory access will be fine without volatile. –  Jan 05 '20 at 22:00
  • `volatile` does *not* bypass CPU or GPU caches, it merely prevents the *compiler* from reordering assembly code and from eliding loads and stores. I agree with @JVApen that you probably want to use `std::atomic` instead. – G. Sliepen Jan 06 '20 at 09:58