volatile struct = struct not possible, why?

后端 未结 3 761
粉色の甜心
粉色の甜心 2021-01-01 13:26
struct FOO{
    int a;
    int b;
    int c;
};

volatile struct FOO foo;

int main(void)
{
    foo.a = 10;
    foo.b = 10;
    foo.c = 10;
    struct FOO test = foo         


        
相关标签:
3条回答
  • 2021-01-01 13:40

    This is ill-formed because FOO has an implicit copy constructor defined as:

    FOO(FOO const&);
    

    And you write FOO test = foo; with foo of type volatile FOO, invoking:

    FOO(volatile FOO const&);
    

    But references-to-volatile to references-to-non-volatile implicit conversion is ill-formed.

    From here, two solutions emerge:

    1. don't make volatile to non-volatile conversions;
    2. define a suited copy constructor or copy the object members "manually";
    3. const_cast can remove the volatile qualifier, but this is undefined behavior to use that if your underlying object is effectively volatile.

    Could I possibly use memcopy() for that?

    No you cannot, memcpy is incompatible with volatile objects: thre is no overload of it which takes pointers-to-volatile, and there is nothing you can do without invoking undefined behavior.

    So, as a conclusion, your best shot if you cannot add a constructor to FOO is to define:

    FOO FOO_copy(FOO volatile const& other)
    {
        FOO result;
        result.a = other.a;
        result.b = other.b;
        result.c = other.c;
        return result;
    }
    

    Or with C++11's std::tie:

    FOO FOO_copy(FOO volatile const& other)
    {
        FOO result;
        std::tie(result.a, result.b, result.c) = std::tie(other.a, other.b, other.c);
        return result;
    }
    
    0 讨论(0)
  • 2021-01-01 13:40

    To give another approach to an answer, to address why this doesn't make sense, rather than just where the C++ standard says this is invalid:

    The whole point of volatile is that you have precise control over which variable gets accessed when. That means given volatile int i, j;, i = 1; j = 2; and j = 2; i = 1; do not do the same thing. The compiler cannot freely transform one into the other. The same applies to reads: given volatile int i, j; int x, y;, x = i; y = j; and y = j; x = i; do not do the same thing. The presence of volatile means the accesses must happen in exactly the order you specified.

    Now, in your example, what should struct FOO test = foo; do? You've never specified whether you want to first read foo.a, then foo.b, finally foo.c, or perhaps first read foo.c, then foo.b, finally foo.a, or perhaps some other order.

    You can, if you wish, do this:

    struct FOO test;
    test.a = foo.a;
    test.b = foo.b;
    test.c = foo.c;
    

    Here, you explicitly specify the order of the accesses to foo's fields, so you avoid the problem.

    0 讨论(0)
  • 2021-01-01 13:41

    You haven't provided enough details about your problem to give a more precise assessment, but the solution to whatever problem you're trying to solve is almost certainly not to use volatile. "Volatile" means that the value can change from under your feet: the two typical good use cases are variables changed from within UNIX signal handlers and memory-mapped registers. Volatile is not enough for variables shared among threads, notably.

    The reason you are getting this error is that your compiler is trying to find a FOO(volatile FOO&) copy constructor, which is never automatically generated.

    0 讨论(0)
提交回复
热议问题