无法从指向多态类的指针映射获取有效的指针

Unable to get valid pointers from std::map of pointers to Polymorphic classes

本文关键字:指针 映射 获取 有效 多态      更新时间:2023-10-16

在尝试为一组多态类实现容器(映射(时,我一直在与分段错误作斗争,boost::ptr_map似乎是正确管理内存的一种可能解决方案,但在更改实现之前,我想了解我做错了什么。

假设我有以下抽象类和两个派生类:

class Base {
 public:
    virtual ~Base() {};
    virtual void getClassName() = 0;
}
class Derived1 : public Base {
 public:
     void getClassName() { std::cout << "Derived1n";}
}
class Derived2 : public Base {
 public:
     void getClassName() { std::cout << "Derived2n";}
}

现在假设我们有这两个版本的容器用于这些类。我预计一个在尝试取消引用指针时失败(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

如果需要

增加容量,push_back会使vector的迭代器失效。因此,使用 &dataDerived1.back() 不是一个好主意 - 地址可能会更改。如果需要使用指针,请将PointerMap设置为map<string, unique_ptr<Base>>,并将Derived1Derived2更改为unique_ptrvector