C++ STL std::映射、将引用传递给const以及const_转换的必要性
我有一个关于STL容器的C++ STL std::映射、将引用传递给const以及const_转换的必要性,c++,stl,const-cast,C++,Stl,Const Cast,我有一个关于STL容器的const_cast和最佳实践的简单问题。考虑下面的代码,其中类 FoO 有一个私有的STL STD::MAP >从代码>小部件*/到代码> int /代码>: 声明: #include <map> using std::map; class Widget; class Foo { public: Foo(int n); virtual ~Foo(); bool hasWidget(const Widget&)
const_cast
和最佳实践的简单问题。考虑下面的代码,其中类<代码> FoO 有一个私有的STL <代码> STD::MAP<代码> >从代码>小部件*/<代码>到代码> int /代码>:
声明:
#include <map>
using std::map;
class Widget;
class Foo {
public:
Foo(int n);
virtual ~Foo();
bool hasWidget(const Widget&);
private:
map<Widget*,int> widget_map;
};
#包括
使用std::map;
类控件;
福班{
公众:
Foo(int n);;
虚拟~Foo();
boolhaswidget(constwidget&);
私人:
地图小工具(map);;
};
定义:
#include <map>
#include "Foo.h"
#include "Widget.h"
using std::map;
Foo::Foo(int n)
{
for (int i = 0; i < n; i++) {
widget_map[new Widget()] = 1;
}
}
Foo::~Foo()
{
map<Widget*, int>::iterator it;
for (it = widget_map.begin(); it != widget_map.end(); it++) {
delete it->first;
}
}
bool Foo::hasWidget(const Widget& w)
{
map<Widget*, int>::iterator it;
it = this->widget_map.find(const_cast<Widget*>(&w));
return ( ! ( it == widget_map.end() ) );
}
#包括
#包括“Foo.h”
#包括“Widget.h”
使用std::map;
Foo::Foo(int n)
{
对于(int i=0;i首先;
}
}
bool-Foo::hasWidget(const-Widget&w)
{
对它进行迭代器;
it=this->widget_map.find(const_cast&w));
return(!(it==widget_map.end());
}
假设hasWidget
将对const的引用作为其参数,那么在调用map::find
(wiget\u-map
是从wiget*
到int
)时,需要丢弃constness。据我所知,这种方法既明智又合意——但我不愿意接受它,而不需要有经验的C++程序员的反馈。p>
在我看来,这是适当使用const_cast
的少数情况之一,因为我们正在将cast的结果传递给STL方法。我说得对吗
我意识到这个问题的其他排列已经提出(例如),但似乎没有一个能直接解决上述问题
提前谢谢。我想通过我的回答,我会陷入“主观和争论”的境地,但我会尝试一下 我对
const_cast
并不感到恐惧,但我对你的设计持怀疑态度。成员函数hasWidget
通过const ref获取其参数:这对客户端意味着什么?从客户机的角度来看,如果我不知道实现,我可能会认为每个小部件
都通过值与参数进行比较。对我来说,界面并不反映实际的行为,它通过地址比较小部件
例如,当前签名允许传递一个临时的小部件
,尽管在这种情况下返回值永远不能是true
。我个人会将签名更改为(注意,我添加了一个const
):
为什么不使用地图
?您似乎从未修改地图中任何键指向的小部件
假设有充分的理由那么是的,我认为你是对的。当调用保证不修改指针的refereand的代码时,可以安全地丢弃const。由于指针容器的模板化方式,它们的函数都不会直接修改refereand,但是如果包含的类型是常量指针,那么用户也无法修改refereand(没有常量转换)。当然,在搜索之前丢弃常量比在修改之前丢弃常量更安全,如果它必须是以下两种之一
顺便说一句,如果使用count
而不是find
,那么hasWidget
会更短。通常使用count
也稍微安全一些(在本例中不是这样),因为find
与此const\u cast
一起返回一个迭代器,可以用来修改小部件,而count
不返回。因此,您不必担心count的返回值会发生什么变化。显然,无论如何,返回值都是完全受控的。是的,这是对const\u cast
的合理使用。你应该考虑制作HasWiGue<代码> const .< /P> < p>为什么不更改<代码> HasWigGe< /Cord>以获取<代码>小部件*/代码>?该接口目前是不可靠的,因为它意味着您在底层映射中按值查找小部件,而实际上是按地址查找它们。方法也应该是const
,我认为:
bool hasWidget(Widget *) const;
一个带有键的映射,其中键是指针,这是很难处理的——唯一的查找方法就是使用相同的指针。要使其工作,您必须保证使用具有相同地址的对象调用hasWidget
方法
当然,您应该正确地实现小部件
,使其具有正确的重载运算符,以充当std::map
中的键!在地图中,您只需拥有:
std::map<Widget, int>
std::map
然后你的发现就不需要一个const\u cast
我觉得这个很笨重。通过物理地址识别对象是相当“特殊”的,诚然这是独特的,但也很奇怪
我强烈反对反转地图:
std::map<Widget::Id, Widget*>
这将缓解内存管理问题。这只是对现有代码的抽象——在实际的代码库中,我确实修改了小部件,因此密钥类型是可取的。在进一步讨论了这一点(如上所述)之后,我似乎错了,原来的密钥类型是“可取的”——是时候重构了!您有一个指向小部件
的指针映射,但是小部件
是由Foo
动态创建的,映射是私有的。该类的任何客户端如何神奇地以恰好位于地图中的小部件引用结束?如果Foo
拥有Widget
s,为什么它不使用表示这种所有权的容器呢?我不明白地图的意思。整数是什么意思?@Charles:原来(在回答我的问题时)这不是完整的程序;-)MSDN似乎认为map::find需要一个const键&,因此在这段代码中,您将const小部件*强制转换为
std::map<Widget::Id, Widget*>
boost::ptr_map<Widget::Id, Widget>