从我的上一个问题开始,我有一个抽象基类Action
,它充当执行各种不同操作的接口.为了实现一个抽象层,我有一个ActionHandler类,它在这里存储各种动作:
class ActionHandler
{
public:
ActionHandler();
~ActionHandler();
Action& getAction(std::string ActionString);
private:
boost::ptr_map<std::string, vx::modero::Action> cmdmap;
};
Run Code Online (Sandbox Code Playgroud)
我从上一个问题的回答中了解到,boost会自动处理将任何插入的指针类型(类)释放到此映射中.
所以,我现在尝试插入派生的东西Action
,这发生在ActionHandler(ActionHandler :: ActionHandler)的构造函数中:
ActionHandler::ActionHandler()
{
this->cmdmap.insert("help", new DisplayHelpAction());
};
Run Code Online (Sandbox Code Playgroud)
凡DisplayHelpAction
公开子类Action
.这样做会导致此错误:
error: no matching function for call to ‘boost::ptr_map<std::basic_string<char>,
Action>::insert(const char [5], DisplayHelpAction*)’
Run Code Online (Sandbox Code Playgroud)
现在,从这里我使用的方法是:
std::pair<iterator,bool> insert( key_type& k, T* x );
Run Code Online (Sandbox Code Playgroud)
所以我可以看到,使用多态在这里应该工作.我不想使用,boost::any
因为我不希望此列表包含任何类型的指针.它应该符合Action
或不存在指定的接口.
那么,我做错了什么?
我可以依靠简单地使用std::map
并拥有我的析构函数delete
,所以如果这不能合理地实现它不是一个显示塞子.我个人认为shared_ptr
有std::map
可能会更好,但这个已经尝试,我现在有这么-为什么- doesn't-这个工作综合症.
@ Cubbi的答案是正确的,但没有解释为什么这样做.
传统上,const&
除非它们是内置的,否则这些参数都是采用的,因此人们自然会期望:
insert(key_type const&, value*)
Run Code Online (Sandbox Code Playgroud)
这自然会允许:
someMap.insert("abc", new DerivedAction());
Run Code Online (Sandbox Code Playgroud)
但作者选择了签名:
insert(key_type&, value*)
Run Code Online (Sandbox Code Playgroud)
是的,这是故意的.
问题是带有原始指针的表单应该与内联 一起使用new
,如您在自己的示例中所示,但是存在异常安全问题.
你可以在本周的大师看到Sutter对它的看法.
在C++中调用函数时,应在调用开始之前评估其所有参数,并且未指定参数的评估顺序.因此,如果参数的评估执行内存分配和另一个操作(可能抛出),则存在风险.在你的例子中:
insert("abc", new DerivedAction());
// equivalent to
insert(std::string("abc"), new DerivedAction());
Run Code Online (Sandbox Code Playgroud)
在执行调用之前,有两个操作要做(以未指定的顺序):
"abc"
为std::string
DerivedAction
物体的免费商店建设如果转换"abc"
为std::string
抛出,并且在内存分配后进行了调度,则内存被泄露,因为您无法释放它.
通过强制第一个参数不是临时的,他们防止了这个错误.这是不够的(通常),因为任何函数调用都可以执行并仍然抛出,但它确实让你思考,不是吗:)?
注意:auto_ptr
采用引用的版本反之亦然,它们会强制您事先分配内存,因此"abc"
可能抛出的转换不再是风险,因为RAII将确保正确清理
正如您所指出的,您正在调用的方法是
std::pair<iterator,bool> insert( key_type& k, T* x );
Run Code Online (Sandbox Code Playgroud)
但第一个参数不是可以绑定到非const引用的类型std::string
.您必须将密钥设为左值
std::string key = "help";
cmdmap.insert(key, new DisplayHelpAction());
Run Code Online (Sandbox Code Playgroud)
或者使用带有const引用的表单(为了异常安全,仍然必须是两行)
std::auto_ptr<DisplayHelpAction> ptr(new DisplayHelpAction());
cmdmap.insert("help", ptr);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1548 次 |
最近记录: |