列表插入迭代器超出范围 (C++)

List insert iterator outside range (C++)

我有一个 class A 可以响应 doSomething() 和一些子 classes B, CD 全部覆盖 doSomething()B 特别有一个实例变量,它是标准库中的列表,并在响应 doSomething().

时向该列表添加元素

在我的代码的某些部分,我创建了一个数组,其中包含指向 A 类型对象的指针。现在,如果我这样声明:

A* pointersToA[3];
pointersToA[0] = &B();
pointersToA[1] = &C();
pointersToA[2] = &D();

我在调用 pointersToA[0]->doSomething() 时收到 List insert iterator outside range

但如果我这样做:

A* pointersToA[3];
B b = B();
pointersToA[0] = &b;
pointersToA[1] = &C();
pointersToA[2] = &D();

一切正常。

为什么会这样?

获取右值的地址几乎肯定迟早会导致问题(通常更早),并且在 C++ 中实际上是非法的(因此您的编译器在这方面并不是一流的)。地址不是对对象的 strong 引用;因为 C++ 不是垃圾收集语言,所以 BCD 的值在执行它们所用的语句后立即消失。

对于您的使用来说,动态分配听起来是最直接的方式:

std::array<std::unique_ptr<A>, 3> pointersToA {
    std::make_unique<B>(),
    std::make_unique<C>(),
    std::make_unique<D>()
};

当你这样做时:

pointersToA[0] = &B();

您正在 pointersToA[0] 中存储一个指向临时对象的指针。这在标准 C++ 中是无效的,符合标准的实现应该会发出错误。事实上,这个适合您的编译器表明您的编译器有错误或非标准扩展。

鉴于您的编译器接受该代码,问题是在那行之后,pointersToA[0] 无效,因为它指向的 B 对象不再存在。取消引用该指针是 未定义的行为

当你这样做时

B b = B();
pointersToA[0] = &b;

你存储了一个指向对象 b 的指针。只要 b 还活着,就可以通过 pointersToA[0].

访问它

注意: 最好在编译器中禁用此 "extension" 以避免 运行 进入这种类型问题。

pointersToA[0] = &B();

这将创建一个临时对象,调用其构造函数,将指向该对象的指针存储在 pointersToA[0] 中,然后销毁临时对象,调用其析构函数。从这点来看,pointersToA[]中存储的指针不再有效,使用它是未定义的行为。

B b = B();
pointersToA[0] = &b;

在这里,对象继续存在,直到这个范围结束,使用这个指针,取消引用它,调用它的方法,是一个有效的操作,直到范围结束,对象被销毁。

您收到的错误消息是由于未定义的行为造成的。 "Undefined behavior" 意味着什么:代码仍然运行,产生正确的结果;或者代码仍然运行,产生垃圾结果;或者代码因一些随机错误而失败;或者你的整个计算机着火并爆炸​​。

如果你想创建一个指针并存储它,你将需要一个智能指针class或new。你实际上在做的是创建一个临时对象,然后将指针存储到它曾经所在的位置,所以当你调用 b::doSomething() 时,你正在调用一个已经被破坏的对象。

#include <iostream>
class base {};
class derived : public base {
public:
    derived() { std::cout << "constructed" << std::endl;}
    ~derived() { std::cout << "destructed" << std::endl;}
};

int main(){
    base *pointers[3];
    pointers[0] = &derived();
    std::cout << "pointer assigned" << std::endl;
    return 0;
};

输出:

constructed
destructed
pointer assigned