gpt4 book ai didi

c++ - 具有强异常保证的同步 STL 容器插入

转载 作者:行者123 更新时间:2023-12-02 10:29:14 24 4
gpt4 key购买 nike

我想同时插入几个 STL 容器,要么全部成功,要么全部保持不变。我怎样才能优雅地做到这一点?
在我的示例中,我有一个自定义容器,其中包含各种 STL 容器作为数据成员。插入操作插入到各种容器中,但如果其中一个失败,则需要撤消更改以确保所有不变量仍然有效。我该怎么做(很好)?
我的第一个直觉是回溯所有插入并撤消它们。尽管我希望我的例子能说明这一点,但这似乎有些过分。
示例(对不起,如果不是“足够小”):

struct DataItem {
int x;
float y;
char c;
};

class MyContainer {
public:
void Insert(std::vector<std::string> names,
std::unordered_set<int> categories,
DataItem data);
private:
/* invariant: if a string 'name' is mapped to an id 'i' in 'name_to_id_'
it must be the position of a 'DataItem' object in 'data_'
and contained in at least one of the categories */
std::map<std::string, int> name_to_id_;
std::map<int, std::unordered_set<int>> categories_;
std::vector<DataItem> data_;
};

MyContainer::Insert(std::vector<std::string> names,
std::unordered_set<Categories> categories,
DataItem data) {
/* ensure names, and categories are not empty and data is valid */
int id = data_.size();
for (auto it = names.begin(); it != names.end(); ++it) {
if (this->name_to_id_.count(name)) {
/* Clean up all names inserted so far by iterating backwards to names.begin()
using this->name_to_id_.erase */
throw SomeException("Insertion failed");
}
try {
this->name_to_id_.insert({*it, id});
} catch (/* what do I catch here? */) {
/* Clean up all names inserted so far by iterating backwards to names.begin()
using this->name_to_id_.erase */
throw SomeException("Insertion failed");
}
}
for (auto it = categories.begin(); it != categories.end(); ++it) {
try {
this->categories_.at(*it).insert(id);
} catch (/* what do I catch here? */) {
/* Clean up all names and all categories id was inserted into so far by
iterating backwards to categories.begin() using
this->categories_.at(*it).erase(id) */
throw SomeException("Insertion failed");
}
}
try {
this->data_.push_back(data);
} catch (/* what do I catch here? */) {
/* Once again clean up all categories and names... */
throw SomeException("Insertion failed");
}
}
即使没有写出清理工作,这似乎也太过分了。特别是考虑到 insertpush_back应该很少失败。这真的是我需要做的吗?
此外,我可以为 std::unordered_set 确定最安全的删除更改的方法。的和 std::mapfind 的组合和 erase ,但我在 find 上找不到任何内容的异常安全。它总是成功吗?
我突然想到 insertpush_back语句必须包含在 try 中 block 来真正处理异常,但是我捕获了什么异常?

最佳答案

我没有解决实际的清理操作,也没有解决最有效的方法。您将需要记录插入失败的阶段并相应地继续。

struct DataItem {
int x;
float y;
char c;
};

class SomeException : std::exception
{
public:
SomeException(char *c) : std::exception(c) {};

};

class MyContainer {
public:
void Insert(std::vector<std::string> names,
std::unordered_set<int> categories,
DataItem data);

private:
void CleanUp();

private:
/* invariant: if a string 'name' is mapped to an id 'i' in 'name_to_id_'
it must be the position of a 'DataItem' object in 'data_'
and contained in at least one of the categories */
std::map<std::string, int> name_to_id_;
std::map<int, std::unordered_set<int>> categories_;
std::vector<DataItem> data_;
};


void MyContainer::CleanUp()
{
// Do your clean up here
}

void MyContainer::Insert(std::vector<std::string> names,
std::unordered_set<int> categories,
DataItem data)
{
bool failed = false;

/* ensure names, and categories are not empty and data is valid */
int id = data_.size();
for (auto it = names.begin(); it != names.end() && !failed; ++it) {
if (this->name_to_id_.count(*it))
failed = true;
try {
this->name_to_id_.insert({ *it, id });
}
catch (...) {
failed = true;
}
}

for (auto it = categories.begin(); it != categories.end() && !failed; ++it) {
try {
this->categories_.at(*it).insert(id);
}
catch (...) {
failed = true;
}
}

try {
if (!failed)
this->data_.push_back(data);
}
catch (...) {
failed = true;
}

if (failed)
CleanUp();
}

关于c++ - 具有强异常保证的同步 STL 容器插入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62970606/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com