无法从指向多态类的指针的std :: map获取有效指针

时间:2014-12-16 19:33:08

标签: c++ pointers polymorphism

在尝试为一组多态类实现容器(映射)时,我一直在努力解决分段错误,而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

1 个答案:

答案 0 :(得分:1)

如果需要增加容量,

push_back将使vector的迭代器无效。因此,使用&dataDerived1.back()不是一个好主意 - 地址可能会改变。如果您需要使用指针,请PointerMap map<string, unique_ptr<Base>>并将Derived1Derived2更改为vector的{​​{1}}。< / p>