简体   繁体   English

调整std :: vector的大小<AbstractClass*>

[英]Resize a std::vector<AbstractClass*>

It is my understanding that we can never instantiate an abstract class in C++ or equally an interface in Java . 据我了解,我们永远无法实例化C++的抽象类或Java的接口。 This makes sense because we have "pure virtual" functions that provide no implementation, therefore we can only instantiate subclasses of this class/interface that adhere to the contract formed by the abstract class. 这是有道理的,因为我们有不提供任何实现的“纯虚拟”函数,因此我们只能实例化此类类/接口的子类,这些子类遵守由抽象类形成的协定。 Consider the following code: 考虑以下代码:

#include <iostream>
#include <vector>

using namespace std;

class AbstractClass {
public:
  AbstractClass() {
    cout << "Instantiating" << endl;
  }

  virtual void pureVirtualFunction() = 0;

  void testMe() {
    cout << "test" << endl;
  }
};

int main() {
  vector<AbstractClass*> v;
  v.resize(100);
  cout << v.size() << endl;
  v[0]->testMe();
  v[0]->pureVirtualFunction(); //segfault on my machine
  return 0;
}

What baffles me when I run this on my computer is that I can actually resize the vector. 当我在计算机上运行此命令时,令我感到困惑的是我实际上可以调整向量的大小。 I always thought that std::vector::resize instantiated some number of elements, thus calling each element's constructor but further research shows that the constructor is not actually called (also evident by my stdout not showing 100x "Instantiating" strings). 我一直以为std::vector::resize实例化了一些元素,因此调用了每个元素的构造函数,但进一步的研究表明该构造函数并未被实际调用(我的stdout也没有显示100x“ Instantiating”字符串也很明显)。

So if std::vector::resize allocates space for these new objects, and allows me to actually call methods on each of them, how are they not fully instantiated? 因此,如果std::vector::resize为这些新对象分配空间,并允许我实际在每个对象上调用方法,那么它们如何不完全实例化? I figured I couldn't even call resize() on a vector of abstract classes but I can, I assume because they are not fully initialized. 我以为我什至不能在抽象类的向量上调用resize() ,但是我可以,因为它们没有完全初始化。 Could someone explain what is happening here? 有人可以解释这里发生了什么吗?

EDIT: 编辑:

Brain fart..forgot that a vector of pointers, when resized, does not actually allocate new elements, as pointers can be created without allocated elements behind them, however...why can I still call a member function on a pointer to a class in which is not instantiated? 脑子放屁..忘记了指针向量在调整大小时实际上并没有分配new元素,因为可以在没有后面分配元素的情况下创建指针,但是...为什么我仍然可以在指向类的指针上调用成员函数在哪个没有实例化?

The other answers already say what's wrong with your code, I'm here to answer the edit: 其他答案已经说明您的代码出了什么问题,我在这里回答您的修改:

however...why can I still call a member function on a pointer to a class in which is not instantiated? 但是...为什么我仍然可以在未实例化的类的指针上调用成员函数?

You mean this part in particular: 您特别是指这部分:

  v[0]->testMe();
  v[0]->pureVirtualFunction(); //segfault on my machine

Basically, because v[0] doesn't point to a valid object yet trying to call testMe() is already undefined behaviour. 基本上,因为v[0]并不指向有效的对象,但是尝试调用testMe()行为已经是未定义的行为。

The only reason it doesn't segfault is because you're (un)lucky that the compiler rewrote your code. 它不会进行段错误的唯一原因是因为您很不幸编译器重写了您的代码。 Your body of the method testMe() doesn't require the *this object at all and thus the compiler will just replace it with a cout call. 您的方法testMe()主体根本不需要*this对象,因此编译器将仅将其替换为cout调用。 Because no attempt to access some invalid this pointer is made there is no segfault yet. 因为没有尝试访问一些无效的this指针是由没有段错误呢。 Then, when calling the second method the compiler needs to check the vtable of an invalid this pointer, which causes the segfault. 然后,在调用第二种方法时,编译器需要检查无效的this指针的vtable,这将导致segfault。 Don't ever rely on the behaviour of the testMe() working out, this is still undefined behaviour, anything can happen. 永远不要依赖testMe()的行为,这仍然是不确定的行为,任何事情都可能发生。

The value_type of your vector is AbstractClass* - that is, the vector contains pointers which could be nullptr , a pointer to a valid instance of AbstractClass deriviation or random locations in memory. vectorvalue_typeAbstractClass* -也就是说,向量包含的指针可能为nullptr ,即指向AbstractClass派生的有效实例或内存中随机位置的指针。

vector::resize(N) creates N default-initialized elements, and again, the value_type of your vector is something * , so it will create N instances of nullptr . vector::resize(N)创建N默认初始化的元素,并且向量的value_type同样是* ,因此它将创建Nnullptr实例。

AbstractClass::testMe is a non-virtual member function. AbstractClass::testMe是一个非虚拟成员函数。 Thus, under the hood, it is simply a plain function that takes a hidden this pointer as its first argument. 因此,在底层,它只是一个简单的函数,将隐藏的this指针作为其第一个参数。

The body of testMe itself does not access any elements of the abstract class, so it never dereferences this . testMe主体本身不访问抽象类的任何元素,因此它永远不会取消引用 this

Thus 从而

v[0]->testMe();

calls AbstractClass::testMe(nullptr, ); 调用AbstractClass::testMe(nullptr, ); and never dereferences this . 并且从不取消引用this

v[0]->pureVirtualFunction(); //segfault on my machine

tries to dereference nullptr to find v[0] s vtable => crash. 尝试取消引用nullptr来查找v[0]的vtable =>崩溃。

You made a vector of AbstractClass * , not of AbstractClass . 您创建了AbstractClass *的向量,而不是AbstractClass的向量。

Pointers can be created without objects to point to. 可以创建没有指向对象的指针。

Because of the function being virtual, those pointers could point to derived classes' objects which are no longer abstract, so the call would be legal. 由于该函数是虚拟的,所以这些指针可能指向不再抽象的派生类的对象,因此该调用将是合法的。
Only when you finally execute it, the system trips over the null in the vptr table and dumps. 仅当最终执行它时,系统才会越过vptr表中的null并转储。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM