STL map:访问读取位置时出现访问冲突

4

这是我的代码:

class Base
{
public:
    virtual void show() const = 0;
};

class Child : public Base
{
private:
    static const int i = 1;
public:
    virtual void show() const
    {
        cout << i;
    }
};

map<int, const Base &> myMap{
    { 0, Child() },
    { 1, Child() },
};

Base & b = Child();

int main()
{
    b.show();

    myMap.at(0).show(); // This provokes the error

    system("pause>NUL");
    return 0;
}

正如您所看到的,我正在尝试使用全局(或静态)数据,该数据将调用一些虚拟函数。当我测试Base & b = Child();并在main中:b.show();,一切都很好。
但是,如果我像上面那样使用map,我会遇到错误:

0xC0000005: 访问位置0x00000000时发生访问冲突

我尝试调试这段代码,并发现当它到达myMap.at(0).show();时,我得到了这个:
enter image description here 表明虚拟函数表无法读取...
然后我尝试使用指针:
map<int, Base *>{0, new Child()}
这行得通。
因此,似乎这个错误来自于临时引用。
但是我不知道为什么b可以工作。 b也是一个临时引用。 在我看来,这个map包含了许多b。 为什么b可以工作而map不行呢?

定义一个虚析构函数。 - Banex
1
@Banex 虽然这通常是一个好主意,但在这里并不必要,也与问题无关。 - Konrad Rudolph
你使用的编译器是什么?我的Clang拒绝了这个:引用映射和对临时变量的引用... - Serge Ballesta
@Banex 我已经为这两个类添加了虚析构函数,但是我还是得到了错误。 - Yves
1
@SergeBallesta:Visual Studio作为扩展允许引用临时变量。这并不意味着使用它是一个好主意。遵循编码标准!! - Lightness Races in Orbit
2个回答

7
您有一个对临时变量的引用映射。我很惊讶,即使编译了也没有被删除。
map<int, Base &> myMap{
    { 0, Child() },
    { 1, Child() },
};

放弃引用并切换到 unique_ptr

std::map<int, std::unique_ptr<Base>> myMap;

你可以使用这种方法将元素插入到此地图中。这样可以防止对象切割
你在这里再次做同样的事情。
Base & b = Child();

你不能持有对临时对象的非常量引用


1
谢谢。这个可以编译,因为我正在使用愚蠢的微软Visual Studio。 - Yves
你使用的是哪个版本的Visual Studio?它应该至少在2010年以上。 - Paani
@Tomas "你在这里又做了同样的事情 Base & b = Child();" - SChepurin
似乎你在谈论引用和智能指针...我也尝试过这样:map<int,const Base&>,但我仍然得到同样的错误。我不知道为什么。 - Yves
@SChepurin 谢谢大家。关于你们正在讨论的问题,我现在完全明白了。但这与我的问题无关... 我已经尝试过 map<int, const Base &> 但仍然遇到了相同的错误。 - Yves
显示剩余4条评论

0

MSVC允许将临时对象赋值给引用,这意味着Base & b = Child();是被接受并正确处理的,尽管它不是标准C++,其他编译器会拒绝它(以后的MSVC版本也可能拒绝)。

但即使是MSVC也不接受引用类型的STL容器。

因此,你应该使用map<int, Base>(不使用引用,存储对象的副本),或者使用map<int, Base *>(存储对象的指针)。在后一种情况下,你必须显式地处理对象的销毁。你还可以使用智能指针smart pointers,如unique_ptrshared_ptr,让STL自动处理对象的销毁。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接