[英]Strange behaviour with this struct shallow copy?
我已经定义了以下数据结构,其目的是提供一个 get_next() 方法,该方法返回指向下一个 required_configuration 的迭代器。 如果required_explorations
为空或已到达末尾,则返回它指向开头。
#include <iostream>
#include <map>
#include <string>
#include <unordered_map>
using configuration_model = std::unordered_map<std::string, std::string>;
struct doe_model {
inline bool add_config(const std::string& config_id,
const configuration_model& config,
const int required_number_of_observations)
{
bool assignment_took_place = !required_explorations.insert_or_assign(config_id, config).second || !number_of_explorations.insert_or_assign(config_id, required_number_of_observations).second;
next = required_explorations.end();
return assignment_took_place;
}
inline void update_config(const std::string& config_id)
{
number_of_explorations.at(config_id)--;
// remove the configuration in case we exausted all the explorations
if (number_of_explorations.at(config_id) <= 0)
remove_config(config_id);
}
inline void remove_config(const std::string& config_id)
{
required_explorations.erase(config_id);
number_of_explorations.erase(config_id);
}
// this method returns the next configuration to explore
// NOTE: the caller MUST check the pointer first.
inline std::map<std::string, configuration_model>::iterator get_next()
{
// we may have an empty map or one with only a single configuration left
if (required_explorations.empty() || next == required_explorations.end()) {
std::cout << "Required explorations is empty or next at the end(), "
"returning the first pointer."
<< std::endl;
next = required_explorations.begin();
return next;
}
next++;
std::cout << "Returning a next pointer normally." << std::endl;
return next;
}
// key is the configuration_id
std::map<std::string, configuration_model> required_explorations;
std::map<std::string, configuration_model>::iterator next;
std::map<std::string, int> number_of_explorations;
};
我不知道它是为具有这种结构的赋值运算符生成的默认浅拷贝,但测试它我认为问题取决于next
迭代器拷贝。
运行它会按预期返回0
(这是第一个元素)。
int main()
{
doe_model doe;
doe.add_config("0", { { "threads", "29" } }, 4);
doe.add_config("1", { { "threads", "23" } }, 4);
doe.add_config("2", { { "threads", "20" } }, 4);
doe.add_config("3", { { "threads", "21" } }, 4);
doe.add_config("4", { { "threads", "22" } }, 4);
auto it = doe.get_next();
std::cout << it->first << "\t" << std::endl;
}
但运行以下返回4
即结束。
int main()
{
doe_model doe;
doe.add_config("0", { { "threads", "29" } }, 4);
doe.add_config("1", { { "threads", "23" } }, 4);
doe.add_config("2", { { "threads", "20" } }, 4);
doe.add_config("3", { { "threads", "21" } }, 4);
doe.add_config("4", { { "threads", "22" } }, 4);
doe_model new_doe = doe;
auto it = new_doe.get_next();
std::cout << it->first << "\t" << std::endl;
}
有人可以让我了解幕后发生的事情吗?
更新这里是doe_model
使用的真实示例。 有一些数据成员和其他 function 调用我不打算讨论,因为它们并不是真正需要的,以便了解如何使用doe_model
。 当send_configuration
被调用时,它需要从 doe 结构中提取一个新的配置,因此需要get_next
方法来实现该任务返回一个新的配置(与以前的不同,并且仍然具有number_of_explorations > 0
)。
void send_configuration(const client_id_t &name)
{
if (num_configurations_sent_per_iteration <= num_configurations_per_iteration)
{
auto configuration = doe.get_next();
if (configuration != doe.required_explorations.end())
{
remote->send_message(
{MESSAGE_HEADER + "/" + app_id.app_name + "^" + app_id.version + "^" + app_id.block_name + "/" + name + "/explore",
configuration_to_json(configuration->second)});
doe.update_config(configuration->first);
num_configurations_sent_per_iteration++;
}
}
}
next;
被复制,仍然引用另一个实例的required_explorations
。
当您调用get_next()
时,比较next == required_explorations.end()
具有未定义的行为,它仅针对同一容器1的迭代器定义。
另外:在required_explorations
为空的情况下,返回required_explorations.begin()
并取消引用它也有未定义的行为。
end
。 在 C++11 中,您需要容器中的第二个迭代器以确保安全。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.