列表插入迭代器超出范围 (C++)
List insert iterator outside range (C++)
我有一个 class A
可以响应 doSomething()
和一些子 classes B
, C
和 D
全部覆盖 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++ 不是垃圾收集语言,所以 B
、C
和 D
的值在执行它们所用的语句后立即消失。
对于您的使用来说,动态分配听起来是最直接的方式:
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
我有一个 class A
可以响应 doSomething()
和一些子 classes B
, C
和 D
全部覆盖 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++ 不是垃圾收集语言,所以 B
、C
和 D
的值在执行它们所用的语句后立即消失。
对于您的使用来说,动态分配听起来是最直接的方式:
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