Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ STL std::映射、将引用传递给const以及const_转换的必要性_C++_Stl_Const Cast - Fatal编程技术网

C++ STL std::映射、将引用传递给const以及const_转换的必要性

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&)

我有一个关于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&);

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>