Shared memory buffers in C++ without violating strict aliasing rules

后端 未结 3 670
遇见更好的自我
遇见更好的自我 2020-12-16 23:39

I am struggling with implementing a shared memory buffer without breaking C99\'s strict aliasing rules.

Suppose I have some code that processes some data and needs t

相关标签:
3条回答
  • 2020-12-17 00:08

    If a union is used to hold the int and float variables, then you can by pass the strict aliasing. More about this is given in http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html

    Also see the following article.

    http://blog.regehr.org/archives/959

    He gives a way to use unions to do this.

    0 讨论(0)
  • 2020-12-17 00:29

    It is always valid to interpret an object as a sequence of bytes (i.e. it is not an aliasing violation to treat any object pointer as the pointer to the first element of an array of chars), and you can construct an object in any piece of memory that's large enough and suitably aligned.

    So, you can allocate a large array of chars (any signedness), and locate an offset that's aliged at alignof(maxalign_t); now you can interpret that pointer as an object pointer once you've constructed the appropriate object there (e.g. using placement-new in C++).

    You do of course have to make sure not to write into an existing object's memory; in fact, object lifetime is intimately tied to what happens to the memory which represents the object.

    Example:

    char buf[50000];
    
    int main()
    {
        uintptr_t n = reinterpret_cast<uintptr_t>(buf);
        uintptr_t e = reinterpret_cast<uintptr_t>(buf + sizeof buf);
    
        while (n % alignof(maxalign_t) != 0) { ++n; }
    
        assert(e > n + sizeof(T));
    
        T * p = :: new (reinterpret_cast<void*>(n)) T(1, false, 'x');
    
        // ...
    
        p->~T();
    }
    

    Note that memory obtained by malloc or new char[N] is always aligned for maximal alignment (but not more, and you may wish to use over-aligned addresses).

    0 讨论(0)
  • 2020-12-17 00:30

    Actually, what you have written is not a strict aliasing violation.

    C++11 spec 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

    So the thing that causes the undefined behavior is accessing the stored value, not just creating a pointer to it. Your example does not violate anything. It would need to do the next step: float badValue = smem[0]. smem[0] gets the stored value from the shared buffer, creating an aliasing violation.

    Of course, you aren't about to just grab smem[0] before setting it. You are going to write to it first. Assigning to the same memory does not access the stored value, so no ailiasing However, it IS illegal to write over the top of an object while it is still alive. To prove that we are safe, we need object lifespans from 3.8.4:

    A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a non-trivial destructor. For an object of a class type with a non-trivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; ... [continues on regarding consequences of not calling destructors]

    You have a POD type, so trivial destructor, so you can simply declare verbally "the int objects are all at the end of their lifespan, I'm using the space for floats." You then reuse the space for floats, and no aliasing violation occurs.

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