在尝试为一组多态类实现容器(映射)时,我一直在努力解决分段错误,而boost::ptr_map
似乎是一种可以正确管理内存的可能解决方案,但在更改实现之前,我想了解我做错了什么。
假设我有以下抽象类和两个派生类:
class Base {
public:
virtual ~Base() {};
virtual void getClassName() = 0;
}
class Derived1 : public Base {
public:
void getClassName() { std::cout << "Derived1\n";}
}
class Derived2 : public Base {
public:
void getClassName() { std::cout << "Derived2\n";}
}
现在假设我们为这些类提供了这两个版本的容器。我预计在尝试取消引用指针(ContainerSegFault
)时会失败,而另一个似乎做正确的事情(ContainerOk
):
typedef std::map<std::string, Base *> PointerMap;
class ContainerSegFault {
public:
void loadDerived1(){
dataDerived1.push_back(Derived1());
data.insert(std::make_pair("derived1_A", &dataDerived1.back()));
};
Base* getPointer(const std::string& key) {
return data[key];
}
PointerMap data;
std::vector<Derived1> dataDerived1;
std::vector<Derived2> dataDerived2;
}
class ContainerOk {
public:
void loadDerived1(){
data.insert(std::make_pair("derived1_A", static_cast<Base *>(new Derived1())));
};
Base* getPointer(const std::string& key) {
return data[key];
}
PointerMap data;
}
如果我尝试取消引用ContainerSegFault
中的指针,就像这样:
ContainerSegFault containerFail;
containerFail.loadDerived1();
Derived1* pDerived1 = static_cast<Derived *>containerFail.getPointer("derived1_A");
pDerived1->getClassName();
我有一个分段错误(即我似乎总是从调用std::map::operator[]
获得未初始化的指针)。如果我使用类ContainerOk
,这个错误似乎就消失了,如下所示:
ContainerOk container;
container.loadDerived1();
Derived1* pDerived1 = static_cast<Derived *>container.getPointer("derived1_A");
pDerived1->getClassName(); // Works ok
我的理解是,在ContainerSegFault
中,我安全地分配了内存
在std::vector<Derived1>::push_back
中调用对象构造函数时
方法,但显然情况并非如此。所以现在我的问题是,是什么
使用默认构造函数(然后将指针存储到向量的最后位置)和new
运算符之间的本质区别?而且,在ContaierOk
的情况下,实际存储的对象在哪里?
非常感谢本期中的任何澄清
@Tryskele
答案 0 :(得分:1)
push_back
将使vector
的迭代器无效。因此,使用&dataDerived1.back()
不是一个好主意 - 地址可能会改变。如果您需要使用指针,请PointerMap
map<string, unique_ptr<Base>>
并将Derived1
和Derived2
更改为vector
的{{1}}。< / p>