Search code examples
c++volatilec++-chrono

Volatile objects of std::chrono::duration type


I do have a program which makes use of volatile-qualified std::chrono::duration objects. Apparently, such objects become very hard to use. For example, following simple program produces compilation error (on gcc and clang):

#include <chrono>

volatile std::chrono::nanoseconds s;

void foo(std::chrono::nanoseconds k) {
    s = k;
}

error: passing 'volatile nanoseconds' {aka 'volatile std::chrono::duration >'} as 'this' argument discards qualifiers [-fpermissive]

It is obvious why I have this error given the interface of the class, and I also know how to hakishly make it "work" (undefined-behavior wise) with const_cast.

Having said that, can absence of volatile-qualified members of std::chrono::duration considered to be a defect? After all, volatile is a perfectly legal C++ construct, and although rare in use, has it's applications.

P.S. I would like to leave the wisdom of volatile-qualification outside of this question, but my crystal ball tells me it is not to be, so to preempt all 'you do not need volatile because it is not thread-safe' mantra, let's consider the case of a signal handler.


Solution

  • Except for very low level facilities, the std::lib doesn't really deal with volatile at all. One could argue that chrono is so low-level that it should handle volatile qualifications. I don't know if the committee would buy that argument or not.

    One can work around such restrictions. You mentioned const_cast. I'd actually recommend casting back and forth from the underlying integral type. It is one of the very few circumstances where I recommend doing so. And it could be encapsulated in a little function:

    #include <chrono>
    
    volatile std::chrono::nanoseconds::rep s;
    
    void
    set_s(std::chrono::nanoseconds k)
    {
        s = k.count();
    }
    
    std::chrono::nanoseconds
    get_s()
    {
        return std::chrono::nanoseconds{s};
    }
    
    void foo(std::chrono::nanoseconds k) {
        set_s(k);
    }