简体   繁体   English

为什么成员函数中的“ this”指针为空?

[英]Why is my “this” pointer inside a member function null?

I don't want to show you a book so i am going to simplify. 我不想给你看一本书,所以我要简化一下。 I have a class called "Tile" that looks similar to this: 我有一个名为“ Tile”的类,它看起来与此类似:

class Tile{
public:
   struct Type{ unsigned int uvIndex; ... };
   Tile(Tile::Type* tt){ tt_ = tt; ... }
   Type tt_ = nullptr;
   Tile* getNorthEast(){
       printf("this %p\n", this); //for debugging purposes
       /* calculation; "this" pointer is need for that  */
       return northEastTilePtr;
   }
};

I want to allocate many of them in one big array that will never move again (no need for a ) so i do that allocation manually 我想将它们中的许多分配在一个不会再移动的大数组中(不需要),所以我手动进行分配

//Manual allocation to prevent constructor from being called
Tile* tiles = (Tile*)malloc(numTiles*sizeof(Tile));
if(tiles == nullptr) throw std::bad_alloc();

Since the Tile type is not known at first i cannot call new to do that. 由于起初不知道Tile类型,因此我无法调用new来做到这一点。 Now i have memory allocated, but no constructors called. 现在我已经分配了内存,但是没有调用构造函数。 The world generator runs and calls for each tile 世界生成器运行并要求每个图块

tiles[tileIndex] = Tile(tileTypePtr);

Now it should have created all objects with all types. 现在它应该已经创建了所有类型的所有对象。 If I render the scene and without calling getNorthEast(); 如果渲染场景并且不调用getNorthEast(); I can see, that the types have been set correctly due to the uvIndex (that just specifies which section of the texture to render). 我可以看到,由于uvIndex (仅指定要渲染的纹理的哪一部分),因此类型设置正确。 So tt_ is set correctly and the constructor must have run correctly too. 因此tt_设置正确,构造函数也必须正确运行。 However! 然而! If i now call getNorthEast(); 如果我现在打电话给getNorthEast(); the printf statement tells me that the this pointer is 00000000 . printf语句告诉我, this指针为00000000 This messes up the calculation and results in a crash. 这会使计算混乱,并导致崩溃。

It probably is due to undefined behaviour, but I do not see what I am doing wrong... I need your help for that. 可能是由于行为不确定,但是我看不到我做错了什么……我需要您的帮助。

EDIT 1: So I have now had a look at placement new. 编辑1:所以我现在看看新的位置。 I have changed the allocation and assignment to: 我将分配和分配更改为:

//allocation 
tiles = (Tile*)new char[numTiles*sizeof(Tile)];
//assignment
new (&tiles[tileIndex]) Tile(tileTypePtr);

However this is still a nullptr. 但是, this仍然是nullptr。 This time the assignment should be a complete overwrite without undefined behaviour. 这次分配应该是完全覆盖而没有未定义的行为。 The allocation does essentially the same thing as std::vector.reserve() ; 分配与std::vector.reserve()基本上具有相同的作用;

Additional Info: the getNorthEast() is called much later in the main loop. 附加信息:getNorthEast()在主循环中稍后调用。 Right now is just initialisation. 现在只是初始化。 It should therefore have no impact on wether the object is constructed or not. 因此,无论是否构造对象,它都不会有影响。

Edit 2: I have just re-tried using a vector. 编辑2:我刚刚使用向量重试。 same result. 同样的结果。

std::vector<Tile> tiles;
//allocation
tiles_.reserve(numTiles);
//construction for each index
tiles.emplace_back(Tile(tileTypePtr)); 

Since neither vector nor doing it manually worked even with your input, i am starting to suspect the cause is some that I have not mentioned. 由于即使使用您的输入也无法手动执行向量操作或手动操作,因此我开始怀疑原因是我没有提到的。 I will keep looking until I find something else, that could cause trouble. 我会一直寻找直到发现其他可能引起麻烦的东西。

 tiles[tileIndex] = Tile(tileTypePtr); 

What this does is it creates a temporary Tile instance, and then (move-) assigns that temporary into the Tile instance that (is supposed to) exists in the array. 它的作用是创建一个临时的Tile实例,然后将(move-)将该临时实例分配给数组中应该存在的Tile实例。 But that Tile instance doesn't exist, so the behaviour of the program is undefined. 但是那个Tile实例不存在,所以程序的行为是不确定的。

Here is a correct way to construct an object into a pre-existing memory buffer: 这是将对象构造到预先存在的内存缓冲区中的正确方法:

 // you can use malloc, but I see no reason to need it
 unsigned char *buffer = new unsigned char[numTiles*sizeof(Tile)];
 auto offset = sizeof(Tile) * tileIndex;
 Tile* tptr = new(buffer + offset) Tile(tileTypePtr);

This syntax that reuses the memory for a new object is called "placement new". 将内存重用于新对象的这种语法称为“ placement new”。 You need to include the <new> header to use it. 您需要包括<new>标头才能使用它。

However, there is no need to re-implement this buffer reuse yourself. 但是,您无需自己重新实现此缓冲区。 std::vector<Tile> does it for you, in addition to taking care of the hazardous memory management as well as the subtleties of exception safety and pointer aliasing rules. std::vector<Tile>可以为您完成此任务,此外还可以处理危险的内存管理以及异常安全性和指针别名规则的微妙之处。 You've already tripped onto one caveat. 您已经绊倒了一个警告。 There is no need to jump onto the next one. 无需跳到下一个。 std::vector is usually the ideal solution for dynamic arrays of non-default-constructible types. std::vector通常是非默认可构造类型的动态数组的理想解决方案。


Edit: The answer below is based on my initial interpretation that you intend to have objects of different types in your array. 编辑:以下答案基于我的初步解释,即您打算在数组中具有不同类型的对象。 I now notice that you have a Type pointer in your object and figure that you might actually be storing only Tile instances with different internal Type pointer (I assume that tt_ is supposed to be a pointer). 现在,我注意到您的对象中有一个Type指针,并且您实际上可能只存储具有不同内部Type指针的Tile实例(我假设tt_应该是一个指针)。

However, your structure seems a bit shaky. 但是,您的结构似乎有些不稳定。 Have you considered how does the user of the array know what type of Tile you have constructed in which index? 您是否考虑过数组的用户如何知道您在哪个索引中构造了哪种类型的Tile Have you considered that all objects in the array must have identical sizes and alignment requirements? 您是否考虑过数组中的所有对象必须具有相同的大小和对齐要求? None of those considerations can be enforced by the compiler. 这些考虑因素都不能由编译器强制执行。

If you know the list of possible tile types beforehand, I suggest using: 如果您事先知道可能的图块类型列表,建议使用:

// let Tile1, Tile2, Tile3 be the possible types
std::vector<std::variant<Tile1,Tile2,Tile3>>

If you cannot constrain the list of types, then you can use: 如果您不能限制类型列表,则可以使用:

std::vector<std::any>

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

相关问题 为什么将成员函数指针与NULL进行比较会产生警告? - Why does comparing a member function pointer to NULL generate a warning? 命名空间中的成员函数指针 - pointer to member function inside namespace 如果指向成员函数的指针为NULL的方法的部分专业化 - Partial specialisation of a method if pointer to a member function is NULL 无法调用结构内的成员函数指针 - Unable to call member function pointer that is inside a struct 调用结构内部的成员函数指针之一 - Call one of a member function pointer inside a struct 如何在对象成员函数内重新分配`this`指针? - How to reassign `this` pointer inside object member function? 当我通过C ++中的空指针调用成员函数时,为什么程序不会崩溃? - Why doesn't the program crash when I call a member function through a null pointer in C++? 为什么带有指针参数的成员 function 需要指向指针的指针? - Why is a member function with a pointer parameter requiring a pointer to a pointer? 为什么我不能访问数组中指向我的成员函数的指针? - Why can't I access the pointer to my member function in my array? 为什么获取成员函数指针值甚至需要从类内部进行类名限定? - Why does taking a member function pointer value requires class name qualification even from inside of the class?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM