假设一个原子变量数组和一个类,它通过重载类[]
- 运算符来调节对该数组的访问,以返回对位置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;
}
我们可以像这样访问array
的元素:
MyClass foo();
int *a = foo[0];
int b = 3;
foo[1] = &b
请注意,默认情况下,使用memory_order_seq_cst
可以访问此类元素。要更改强制执行的内存顺序,可以执行以下操作:
int *a = foo[0].load(memory_order_acquire);
foo[1].store(&b, memory_order_release);
但是如何更改[]
- 运算符的实现,以便memory_order_acquire
用于所有读取,memory_order_release
用于所有写入?我想在[]
- 运算符的定义中执行此操作的原因是,在源中的许多不同位置有很多访问array
的元素,我不想要将已使用的内存排序扩展到所有这些内容。
编辑:正如评论中所讨论的,可以用getter和setter替换[]
- 运算符。但是,这将要求所有访问都被适当的函数替换;加上我是否有可能按照上面概述的方式进行操作。
答案 0 :(得分:4)
您可以使用operator[]
结果的中间参考对象。然后,此对象根据对象在将来表达式中的使用方式应用加载或存储操作。
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)