C++ 从常量c+中检索非常量元素+-矢量
在我的程序中,我有全球数据 每个程序模块必须具有对数据的读写访问权限。到目前为止,我不使用线程,但使用Qt的信号和插槽,因此-尽管我还没有遇到崩溃-我想我需要在某个时候进行同步 因此,每个模块都保存以下数据:C++ 从常量c+中检索非常量元素+-矢量,c++,vector,constants,C++,Vector,Constants,在我的程序中,我有全球数据 每个程序模块必须具有对数据的读写访问权限。到目前为止,我不使用线程,但使用Qt的信号和插槽,因此-尽管我还没有遇到崩溃-我想我需要在某个时候进行同步 因此,每个模块都保存以下数据: const std::vector<T>& data; const std::vector&data; 其中T是一个自定义类。因此,每个模块都可以读取数据。为了保持一致性,向量本身是常量,以禁止并发删除或删除。这些都是使用全局函数(如addToData(T elem
const std::vector<T>& data;
const std::vector&data;
其中T是一个自定义类。因此,每个模块都可以读取数据。为了保持一致性,向量
本身是常量,以禁止并发删除或删除。这些都是使用全局函数(如addToData(T elem)
,removeFromData(int id)
)完成的,这些函数可以同步。请注意,向量本身被声明为通过引用共享,这样,上面一个全局函数中的更改将导致每个程序模块中的数据一致
==>这意味着可以以安全的方式从任何地方读取和添加/删除数据
我遇到的问题是修改数据。T
的设定者知道比赛条件。使用data
,我想允许像data.at(3).setAttr(“hello”)
这样的调用,但是对于常量向量,at()只返回常量引用。我为什么以及如何使它工作?我可以摆脱这种状态,但那感觉不对
考虑到我的架构,我也愿意接受建议。这个场景正是你想要抛弃康斯特内斯的地方。您已经仔细设计了系统,使其能够正常工作,因此,当您完全准备好使用它时,您不必为丢弃
const
而感到不快,因为这是正确的操作
struct no_synchronization {
struct mutex {}
struct guard {
guard(mutex&) {}
};
};
struct serialized {
typedef std::mutex mutex;
typedef std::lock_guard<mutex> guard;
};
template <class T, class S = no_synchronization>
class spaghetti {
typedef typename S::mutex mutex;
typedef typename S::guard guard;
static mutex mutex_;
static std::vector<T> vector_;
template <class F>
static void read_global_vec(F const& f) {
guard lock(mutex_);
std::vector<T> const& ref = vector_;
f(ref);
}
template <class F>
static void write_global_vec(F const& f) {
guard lock(mutex_);
f(vector_);
}
}
struct无同步{
结构互斥体{}
结构防护{
保护(互斥&){}
};
};
结构序列化{
typedef std::互斥体互斥体;
typedef std::锁紧护罩;
};
模板
意大利面{
typedef typename S::mutex mutex;
typedef typename S::警卫;
静态互斥;
静态std::矢量;
模板
静态无效读取\全局\向量(F常量和F){
保护锁(互斥锁);
std::vector const&ref=向量;
f(参考文献);
}
模板
静态无效写入\u全局\u向量(F常量和F){
保护锁(互斥锁);
f(向量_u2;);
}
}
如果向量的内容不经常更改,那么您可以使用带有共享ptr的写时复制来将争用降至最低。因为您需要建议
vector
。这也将消除您提到的全局函数,这是很好的。如果希望类的实例为常量
,请在内部使用可变
向量const\u cast
,但尝试将其隐藏在函数中的某个位置李>
AWRAP类演示
{
公众:
MyCustomClass和GetByIndex(int i)常量//可以抛出
{
std::lock\u guard lock(\u mutex);
返回存储[i];
}
大小\u t大小(整数i)常数
{
std::lock\u guard lock(\u mutex);
返回_storage.size();
}
无效添加(MyCustomClass&addThis)
{
std::lock\u guard lock(\u mutex);
_存储。推回(添加此项);
}
bool Remove(MyCustomClass&removeThis)
{
std::lock\u guard lock(\u mutex);
自动it=_storage.find(删除此项);
if(it==\u storage.end())
返回false;
_存储。擦除(它);
}
模板void ForEach(F const&F)const
{
std::lock\u guard lock(\u mutex);
用于(自动和输入:存储)
f(i);
}
私人:
std::矢量存储;
std::mutex\u mutex;
}
我建议您创建自己的类,该类封装了一个std::vector
,提供所需的同步访问。(并且不具有全局数据)如果修改只与其他修改同步,而不与读取同步,则存在一个数据竞争,即UB。你想要一个读写器锁,或者其他更安全的习惯用法。我猜你是在问如何绕过元素向量和元素向量之间的模糊线;C++并没有使这一点变得简单,不幸的是,当你不使用线程时,我对所有的并发修改和同步的引用有点困惑。似乎您需要防止的只是对向量的递归访问(即,修改向量会导致调用某个函数,该函数会再次尝试修改向量)。这是相关的,但并不完全相同,使用globaladdToData
/removeFromData
函数并不一定有帮助。@BoBTFish向量可能已经有了同步访问,我正在询问向量的元素(也可以是
class AWrapperForDemonstration
{
public:
MyCustomClass& GetByIndex(int i) const // can throw
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage[i];
}
size_t Size(int i) const
{
std::lock_guard<std::mutex> lock(_mutex);
return _storage.size();
}
void Add(MyCustomClass& addThis)
{
std::lock_guard<std::mutex> lock(_mutex);
_storage.push_back(addThis);
}
bool Remove(MyCustomClass& removeThis)
{
std::lock_guard<std::mutex> lock(_mutex);
auto it =_storage.find(removeThis);
if (it == _storage.end())
return false;
_storage.erase(it);
}
template <F> void ForEach(F const& f) const
{
std::lock_guard<std::mutex> lock(_mutex);
for (auto& i : _storage)
f(i);
}
private:
std::vector<MyCustomClass> _storage;
std::mutex _mutex;
}