STL std::map,通过ref传递给const以及const_casting的必要性
我有一个关于 const_cast 的简单问题以及有关 STL 容器的最佳实践。考虑以下情况,其中类 Foo
具有从 Widget*
到 int
的私有 STL std::map
:
声明:
#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;
};
定义:
#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() ) );
}
鉴于 hasWidget
将 const 引用作为其参数,因此在调用 map::find
时需要丢弃 constness(wiget_map
从 Wiget*
到 int
)。据我所知,这种方法既明智又可取——但如果没有更有经验的 C++ 程序员的反馈,我不愿意接受它。
在我看来,这是适当使用 const_cast 的少数情况之一,因为我们将转换结果传递给 STL 方法。我说得对吗?
我意识到这个问题的其他排列已经被提出(例如, const_cast for vector with object),但似乎没有一个直接解决上述问题。
提前致谢。
I have a simple question regarding const_cast
and best practices regarding STL containers. Consider the following where class Foo
has a private STL std::map
from Widget*
to int
:
Declaration:
#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;
};
Definition:
#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() ) );
}
Given that hasWidget
takes a reference to const as its parameter, the constness needs to be cast away when calling map::find
(wiget_map
being from Wiget*
to int
). As far as I can tell, this approach is both sensible and desirable -- but I'm reluctant to accept it as such without feedback from more experienced C++ programmers.
It seems to me that this is one of the few cases of using const_cast
appropriately given that we're passing the result of the cast to an STL method. Am I correct?
I realise that other permutations of this question have been posed already (for example, const_cast for vector with object) but none seem to directly address the above.
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
为什么不改变
hasWidget
来获取Widget*
呢?目前该界面很危险,因为它意味着您正在按底层映射中的值查找小部件,而实际上您是按地址查找它们。我认为该方法也应该是 const:Why not change
hasWidget
to take aWidget*
? The interface is dodgy at the moment, because it implies that you're looking for Widgets by value in the underlying map, when you're actually looking for them by address. The method should also beconst
, I reckon:带有键(键为指针)的映射很笨重 - 查找它的唯一方法是拥有相同的指针。为此,您必须保证使用具有相同地址的对象调用
hasWidget
方法!当然,您应该正确实现
Widget
,以便它重载正确的运算符以充当std::map
中的键!在你的地图中,你可以简单地拥有:然后你的发现不需要
const_cast
!A map with a key where the key is pointer is unwieldy - the only way to look it up is to have the same pointer. For this to work, you have to guarantee that the the
hasWidget
method will get called with an object that has the same address!Surely you should implement
Widget
properly such that it has the correct operators overloaded to act as a key in astd::map
! In your map, you can then simply have:And then your find doesn't need a
const_cast
!这对我来说看起来很笨重。通过物理地址来识别对象是相当“特殊”的,诚然它是独一无二的,但也很奇怪。
我强烈考虑反转映射:
其中
Widget::Id
可以简单地是int
或类似的。那么const-ness就不会有任何问题了。
要深入研究,您还可以查看 Boost指针容器库:
这将缓解内存管理问题。
This looks clunky to me. Identifying objects by their physical addresses is quite "special", admittedly it's unique, but it's weird too.
I would strongly consider reversing the map:
where
Widget::Id
could simply be anint
or similar.There would not be any issue with the const-ness then.
To delve deeper, you could also have a look at the Boost Pointer Container library:
which would alleviate the memory management issues.
我想我的回答会陷入“主观和争论”,但我会尝试一下......
我并不被
const_cast
吓到,但我对你的设计持怀疑态度。成员函数hasWidget
通过 const ref 获取其参数:这对客户端意味着什么?从客户端的角度来看,如果我不知道实现,我可能会认为每个Widget
都按值与范围。对我来说,界面并不反映实际行为,它通过地址比较Widget
。例如,当前签名允许传递临时
Widget
,尽管在这种情况下返回值永远不可能是true
。我会亲自将签名更改为(请注意,我添加了一个const
):I think I'm going to fall in the 'subjective and argumentative' through my answer, but I'll give it a shot...
I'm not horrified by the
const_cast
, but I'm skeptical on your design. The member functionhasWidget
takes its parameter by const ref : what does this say to the client ? From a client point of view, if I didn't know the implementation, I would probably think that eachWidget
is compared by value with the parameter. For me, the interface does not reflect the actual behavior, which compares theWidget
by address.For example, the current signature allows a temporary
Widget
to be passed, although the return value could never betrue
in this case. I would personally change the signature to (note that I added aconst
) :是的,这是
const_cast
的合理使用。您应该考虑将 hasWidget 设置为const
。Yes, that's a reasonable use of
const_cast<>
. You should consider making hasWidgetconst
.为什么不使用
map
?您似乎从未修改过地图中任何键指向的小部件。假设有充分的理由,那么是的,我认为你是对的。当调用保证不会修改指针的引用对象的代码时,可以安全地放弃 const。由于指针容器的模板化方式,它们的函数都不会直接修改该引用对象,但如果包含的类型是 const 指针,则用户也无法修改该引用对象(无需 const 强制转换)。如果它必须是两者之一,那么在搜索之前抛弃 const 肯定比在修改之前抛弃 const 更安全......
顺便说一句,如果您使用
count<,
hasWidget
会更短/code> 而不是find
。一般来说,使用count
也稍微比 const 更安全(在本例中除外),因为使用此const_cast
的find
返回一个迭代器,该迭代器可以是用于修改 Widget,而count
则不然。所以你不必担心count
的返回值会发生什么。显然,无论如何,返回值都完全受到控制。Why not use a
map<const Widget*,int>
? You don't seem to ever modify the Widget pointed to by any of the keys in your map.Assuming there's a good reason then yes, I think you're right. When calling code which is guaranteed not to modify the referand of the pointer, it's safe to cast away const. Because of the way containers of pointers are templated, none of their functions ever directly modify that referand, but if the contained type were a const pointer, then users wouldn't be able to modify the referand either (without a const cast). It's certainly safer to cast away const before searching, than to cast away const before modifying, if it must be one of the two...
Btw,
hasWidget
would be shorter if you usecount
rather thanfind
. It's also marginally const-safer in general (not in this case) to usecount
, becausefind
with thisconst_cast
returns an iterator that could be used to modify the Widget, whereascount
doesn't. So you don't have to worry what happens to the return value ofcount
. Obviously here that return value is entirely under control anyway.