c++ - 什么时候应该使用 const_iterator 而不是 auto
问题描述
下面是一个示例,我认为说明了最好使用 const_iterator 来“const auto”的情况。这是因为容器不提供 cfind() 函数。有没有其他选择?还是应该使用“const auto”而忽略缺少 const?
std::string GetJobTitle(const std::string& employee)
{
using EmployeeTitles = std::unordered_map<std::string, std::string>;
EmployeeTitles employees = { { "Alice", "Director" },{ "Bob","Manager" } ,{ "Charlie", "Developer" } };
// Option 1. const_iterator is access only:
EmployeeTitles::const_iterator itr = employees.(employee);
if (itr != employees.cend())
{
itr->second = "Project Manager"; // error C2678: The compiler prevents us changing the job tile which is what we want
return itr->second;
}
// Option 2. const auto is more concise but is not as safe:
const auto& itr2 = employees.find(employee);
if (itr2 != employees.cend())
{
itr2->second = "Project Manager"; // employee now has new title - how can we prevent this with the compiler but still use auto?
return itr2->second;
}
return "";
}
解决方案
如果可能的话回避问题
使用const
变量
您的示例并未说明该问题的良好案例。只需对 constness 更具“侵略性”,它就会消失。你根本没有改变employees
,所以正确的解决方案是首先声明它const
:
const EmployeeTitles employees = ...;
这更加安全,因为它可以防止对employees
任何地方的更改,而不仅仅是通过迭代器进行更改。
使用范围划分 const/non-const 代码
如果你不能制作employees
const 因为你只能一块一块地填充它怎么办?例如,因为您从数据库中提取信息?将填充代码移动到构建器函数中。或者对于简单的情况,使用立即调用的 lambda:
const EmployeeTitles employees = [] {
EmployeeTitles employees;
for (const auto& record : database.employees()) {
// Probably some more processing would be done here in the real world.
employees.emplace(record.name(), record.job_title());
}
return employees;
}();
使用const
成员函数
如果employees
是类的成员变量,并且您在成员函数中对其进行迭代,请创建该函数const
。
作为基本规则
每当您遇到此问题或类似问题时,请考虑使用const
变量/函数和/或范围来完全回避它的方法。这将处理大多数情况。
万一碰到了怎么办?
在这种情况下,我会选择您的选项 1:结合地图类型的声明显式声明迭代器。const_iterator
using
它简洁、易读、易于理解,是表达意图的最直接方式。
其他操纵 constness 的解决方案employees
没有那么好,因为这不是你真正关心的。你真正想要的是一个只读的迭代器。摆弄 constnessemployees
只是实现该目标的一种迂回方式。而且迂回的代码更难理解。
另一方面,这并不意味着你会在清晰度方面遇到巨大的问题。尤其std::as_const
是简洁明了。
但是,对于 C++17 之前的代码库,您必须使用const_cast
. 这是一个良性的,因为它添加了const 并且它也不太冗长。但我会根据一般原则避免它,即const_cast
在一段代码中看到 a 乍一看总是有点吓人。正如@Swift 在评论中指出的那样,另一个很好的可能性是实现您自己的as_const
.
推荐阅读
- elasticsearch - Elasticsearch 通过嵌套对象属性聚合
- c# - 球的无限弹跳(Unity)
- react-native - undefined 不是一个函数(评估'_this2.AlertButton()')?
- python - Python Fabric 2 使用标准输入
- c# - 如何取消上下文中所有未保存的数据?使用 EF6 时
- kubernetes - grpc-dart - 如何在 grpc-dart 中设置 HEADER - 我只能通过安全连接来完成
- react-native - 使用 oauth2 登录后如何使重定向 url 起作用
- android - 是否有机会更改 android 中的构建变体运行时间
- pandas - 尝试调用 fit_transform 时自定义类引发错误
- firebase - 使用什么标准将每日数据从 Firebase Crashlytics 传输到 Big-Query