首页 > 解决方案 > 拥有可以指向或引用已在堆栈上分配的不同类型的数据的映射的现代方法

问题描述

使用原始指针,可以这样实现:

#include <iostream>
#include <string>
#include <map>

using namespace std;

class base {
public:
    virtual ~base(){}
};

class derived1 : public base {
public:
    virtual ~derived1(){}
    derived1(const int& other) : val(other) {}
    int val;
};

class derived2 : public base {
public:
    virtual ~derived2(){}
    derived2(const float& other) : val(other) {}
    float val;
};


int main()
{
    derived1 dataA = 4;
    derived2 dataB = 3.0f;

    std::map<std::string, base*> mapOfPointersToData; //Needs to be a pointer because it can be of type deribed1 or derived2. Cant be smart as pointing to stack memory
    mapOfPointersToData["dataA"] = &dataA;
    mapOfPointersToData["dataB"] = &dataB;

    base* result = mapOfPointersToData["dataA"];

    std::cout << dynamic_cast<derived1*>(result)->val << std::endl;

    return 0;
}

这行得通,但有人告诉我,我们应该避免使用原始指针来支持智能指针或引用。

对象永远不能为空,因此使用引用是有意义的。我们可以通过使用变体来解决地图只能存储一种数据类型的问题:

int main()
{
    derived1 dataA = 4;
    derived2 dataB = 3.0f;

    std::map<std::string, std::variant<derived1, derived2>&> mapOfPointersToData; //Cant be constructed
    mapOfPointersToData["dataA"] = dataA;
    mapOfPointersToData["dataB"] = dataB;

    auto result = mapOfPointersToData["dataA"];

    std::cout << std::get<derived1>(result).val << std::endl;

    return 0;
}

但这给出了错误

error: value-initialization of reference type ‘std::variant<derived1, derived2>&

那么存储对不同类型的堆栈数据的引用的最佳方法是什么?

标签: c++referencesmart-pointers

解决方案


这行得通,但有人告诉我,我们应该避免使用原始指针来支持智能指针或引用。

仅当原始指针负责拥有它们所指向的内容时(本质上,如果您必须记住delete或以其他方式释放它们),不鼓励原始指针。在这里,对象具有自动存储持续时间,并且指针不负责清理它们。这是原始指针的合理用例。

对象永远不能为空,因此使用引用是有意义的。

nullptr如果您用于operator[]搜索地图,则地图中的对象可能是。该运算符添加它无法找到的任何元素,并初始化它们(nullptr用于指针)。find如果您不想用空指针使地图膨胀,则可以改用。

那么存储对堆栈数据的引用的最佳方式是什么,可以是不同的类型?

您可能正在寻找std::reference_wrapper适合容器的对象中的哪些包装引用。但是使用base*似乎已经是一个很好的解决方案,因为您的地图并不拥有它最终指向的对象。


推荐阅读