【发布时间】:2019-03-10 22:50:44
【问题描述】:
我不想给你看一本书,所以我要简化一下。 我有一个名为“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;
}
};
我想将它们中的许多分配到一个永远不会再次移动的大数组中(不需要 a )所以我手动进行分配
//Manual allocation to prevent constructor from being called
Tile* tiles = (Tile*)malloc(numTiles*sizeof(Tile));
if(tiles == nullptr) throw std::bad_alloc();
由于最初不知道 Tile 类型,我不能调用 new 来执行此操作。 现在我分配了内存,但没有调用构造函数。 世界生成器运行并调用每个图块
tiles[tileIndex] = Tile(tileTypePtr);
现在它应该已经创建了所有类型的所有对象。
如果我渲染场景并且没有调用getNorthEast();,我可以看到,由于uvIndex(它只是指定要渲染纹理的哪个部分),类型已正确设置。所以 tt_ 设置正确,构造函数也必须正确运行。
然而!如果我现在调用getNorthEast();,printf 语句告诉我this 指针是00000000。这会打乱计算并导致崩溃。
这可能是由于未定义的行为,但我看不出我做错了什么......我需要你的帮助。
编辑 1: 所以我现在看了一下新的安置。 我已将分配和分配更改为:
//allocation
tiles = (Tile*)new char[numTiles*sizeof(Tile)];
//assignment
new (&tiles[tileIndex]) Tile(tileTypePtr);
但是this 仍然是一个空指针。这次分配应该是完全覆盖,没有未定义的行为。分配的作用与std::vector.reserve()基本相同;
附加信息:getNorthEast() 在主循环中的调用要晚得多。现在只是初始化。因此,它应该不会影响对象是否被构造。
编辑 2: 我刚刚重新尝试使用向量。同样的结果。
std::vector<Tile> tiles;
//allocation
tiles_.reserve(numTiles);
//construction for each index
tiles.emplace_back(Tile(tileTypePtr));
由于即使您输入了向量,也没有手动操作,我开始怀疑原因是我没有提到的一些原因。我会继续寻找,直到找到其他可能会引起麻烦的东西。
【问题讨论】:
-
malloc函数只分配内存,它不调用构造函数! 以任何方式使用未构造的对象(包括分配给它们,因为调用对象赋值运算符) 导致undefined behavior。请get a few good books to read 了解如何避免此类问题。 -
tiles[tileIndex] = Tile(tileTypePtr);是错误的,因为tiles[tileIndex]使用了未初始化的对象。您必须先调用构造函数,然后才能分配给它。 -
@Someprogrammerdude "现在我分配了内存,但没有调用构造函数。" 我很确定 OP 已经知道了。
-
//Manual allocation to prevent constructor from being called:为什么?这很奇怪。你应该给出解释。是的,我们需要minimal reproducible example。我们至少需要调用getNorthEast的代码 -
我想将它们中的许多分配到一个永远不会再移动的大数组中(不需要 a )所以我手动进行分配 -- 你知道吗?大多数(如果不是所有)
std::vector的实现都做同样的事情,但要正确使用placement-new。所以你在重新发明轮子,只是你的重新发明被打破了。
标签: c++ class pointers null undefined-behavior