2012-05-09 49 views
5

我有一个boost::ptr_map,它将抽象基类(例如VectorWrapperBase)存储为值,这允许我将字符串映射到不同类型的向量。包含抽象基类的ptr_map的映射对象

boost::ptr_map<std::string, VectorWrapperBase> memory_map; 
//... 
memory_map.insert(str_key, new VectorWrapper<T>()); 

这似乎工作。但是,当我将memory_map作为另一个类的成员并尝试将该类存储在std::map中时,编译失败。

class AgentMemory { 
    //... 
    private: 
    boost::ptr_map<std::string, VectorWrapperBase> memory_map; 
}; 

std::map<std::string, AgentMemory> agent_map; 
//... 
agent_map.insert(std::pair<std::string, AgentMemory>(agent_name, AgentMemory())); 

最后一行失败:

/SOMEPATH/boost_1_48_0/boost/ptr_container/clone_allocator.hpp:34 
    error: cannot allocate an object of abstract type ‘xyz::VectorWrapperBase’ 

作为新的C++,这是令人费解。

嫌疑人错误是地图插入复制AgentMemory对象,涉及克隆ptr_map。由于我的VectorWrapper对象不是cloneable,所以会引发错误。

我的问题是:

  • 为什么会出现错误? (我的怀疑是否接近实际发生的事情?)
  • 我该如何解决这个问题?

为了解决编译错误,我认为以下,但没有使用C多少经验++不能决定哪个更合适:

  1. 取出纯符(= 0),所以VectorWrapperBase是不再是抽象的
    • 这感觉就像一个黑客,因为VectorWrapperBase不应该被实例化
  2. 充分利用VectorWrappers cloneable
    • This seems to work,但在我的使用情况下,只有空容器被分配到顶层映射,所以内层ptr_map内的VectorWrappers不需要被克隆。因此,可克隆性只是为了安抚编译器,并不能反映实际使用情况。
  3. 忘记ptr_map并使用std::mapshared_ptr代替。
    • 我不喜欢这个解决方案,因为我希望矢量包装的生命周期与地图的生命周期相关联。我也有点担心(可能不必要)?在大量多线程应用程序中广泛使用shared_ptr的潜在开销。
+0

你的抽象基类有一个虚拟析构函数吗? – TemplateRex

+0

是的。 .. –

回答

0

声明

agent_map.insert(std::pair<std::string, AgentMemory>(agent_name, AgentMemory())); 

将调用AgentMemory默认构造函数,这反过来将调用boost::ptr_map<std::string, VectorWrapperBase>默认的构造函数,它会尝试调用不存在构造函数摘要基类VectorWrapperBase

所以你必须确保包装或继承VectorWrapperBase的每个构造函数都应该总是构造一个具体的派生类。在你的情况下,选项3(派生类的共享指针映射)可能是明智的,但这取决于你的代码的更大的上下文。

+0

感谢您的解释。令我困惑的是'ptr_map'从空开始,为什么需要调用'VectorWrapperBase'的构造函数? –

+0

@ShawnChin正如我在我的回答中所解释的,带'AgentMemory()'参数的'insert()'调用将生成构造函数调用。 – TemplateRex

+0

也许我误解了,但'VectorWrapperBase'不是'AgentMemory'的成员,所以我不明白为什么应该创建它的一个实例。也就是说,我现在很欣赏'VectorWrapperBase'需要可复制的事实,因为'ptr_map'需要被封装类的拷贝构造函数复制。 –