C++ 通过[]-运算符访问的原子变量的获取/释放语义

C++ 通过[]-运算符访问的原子变量的获取/释放语义,c++,arrays,c++11,shared-memory,C++,Arrays,C++11,Shared Memory,假设一个原子变量数组和一个类,该类通过重载类“[]-运算符来返回对位于idx位置的原子变量的引用,从而控制对该数组的访问: class MyClass { public: MyClass() { //initalize every array element with nullptr for (auto& it : array) { it = nullptr; } } std::ato

假设一个原子变量数组和一个类,该类通过重载类“
[]
-运算符来返回对位于
idx
位置的原子变量的引用,从而控制对该数组的访问:

class MyClass {
public:
    MyClass()
    {
        //initalize every array element with nullptr
        for (auto& it : array) {
            it = nullptr;
        }
    }
    std::atomic<int*>& operator[](const size_t idx)
    {
         //there is some more code here, doing basic safety checks,...
         return array[idx];
    }
private:
    std::array<std::atomic<int*>, 1000> array;

}
请注意,默认情况下,对此类元素的任何访问都将使用
内存\u顺序\u seq\u cst
完成。要更改强制内存顺序,可以执行以下操作:

int *a = foo[0].load(memory_order_acquire);
foo[1].store(&b, memory_order_release);
但是如何更改
[]
-运算符的实现,使
内存\u顺序\u获取
用于所有读取,而
内存\u顺序\u释放
用于所有写入?我之所以要在
[]
-运算符的定义中这样做,是因为在源代码的许多不同位置有许多对
数组
元素的访问,我不想将使用的内存顺序分散到所有这些元素


编辑:如注释中所述,可以用getter和setter替换
[]
-运算符。但是,这将要求所有访问都由适当的函数替换;此外,我还对是否可以按照上面所述的方式进行操作感兴趣。

您可以使用中间引用对象,它是
操作符[]
的结果。然后,该对象根据对象在未来表达式中的使用方式应用加载或存储操作

class MyClass {
    struct Ref {
        std::atomic<int *> &ref_;
        Ref (std::atomic<int *> &r) : ref_(r) {}
        operator int * () const {
            return ref_.load(std::memory_order_acquire);
        }
        int * operator = (int *ptr) const {
            ref_.store(ptr, std::memory_order_release);
            return ptr;
        }
    };
public:
    //...
    Ref operator[](const size_t idx)
    {
         //there is some more code here, doing basic safety checks,...
         return array[idx];
    }
    //...
};

我将为此执行两种不同的方法,并删除
操作符[]
@Jarod42:我也考虑过这一点,但它需要用getter/setter替换[]-操作符的所有用法。当然可能,但不太好。另外,我真的很好奇这是否有可能。
class MyClass {
    struct Ref {
        std::atomic<int *> &ref_;
        Ref (std::atomic<int *> &r) : ref_(r) {}
        operator int * () const {
            return ref_.load(std::memory_order_acquire);
        }
        int * operator = (int *ptr) const {
            ref_.store(ptr, std::memory_order_release);
            return ptr;
        }
    };
public:
    //...
    Ref operator[](const size_t idx)
    {
         //there is some more code here, doing basic safety checks,...
         return array[idx];
    }
    //...
};
MyClass foo;
int *a = foo[0];  // uses conversion operator, load(acquire)
int b = 3;
foo[1] = &b;      // uses assignment operator, store(release)