我不想给你看一本书,所以我要简化。 我有一个名为"Tile"的类,看起来像这样:
class Tile{
public:
struct Type{ unsigned int uvIndex; ... };
Tile(Tile::Type* tt){ tt_ = tt; ... }
Type tt_ = nullptr;
Tile* getNorthEast(){
printf("this %pn", this); //for debugging purposes
/* calculation; "this" pointer is need for that */
return northEastTilePtr;
}
};
我想将其中的许多分配给一个永远不会再移动的大数组(不需要 (,所以我手动进行分配
//Manual allocation to prevent constructor from being called
Tile* tiles = (Tile*)malloc(numTiles*sizeof(Tile));
if(tiles == nullptr) throw std::bad_alloc();
由于起初不知道磁贴类型,因此我无法调用 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));
由于即使使用您的输入,矢量和手动操作都不起作用,因此我开始怀疑原因是我没有提到的一些原因。我会继续寻找,直到我找到其他可能会造成麻烦的东西。
>tiles[tileIndex] = Tile(tileTypePtr);
这样做是创建一个临时Tile
实例,然后 (move-( 将该临时实例分配给数组中(应该(存在的Tile
实例中。但是Tile
实例不存在,因此程序的行为是未定义的。
以下是将对象构造到预先存在的内存缓冲区中的正确方法:
// 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);
这种为新对象重用内存的语法称为"放置新"。您需要包含<new>
标头才能使用它。
但是,没有必要自己重新实现此缓冲区重用。std::vector<Tile>
除了负责危险的内存管理以及异常安全和指针混叠规则的微妙之处外,还为您做到这一点。你已经绊倒了一个警告。没有必要跳到下一个。std::vector
通常是非默认可构造类型的动态数组的理想解决方案。
编辑:下面的答案是基于我的初步解释,即您打算在数组中包含不同类型的对象。我现在注意到您的对象中有一个Type
指针,并且您实际上可能只存储具有不同内部Type
指针的Tile
实例(我假设tt_
应该是一个指针(。
但是,您的结构似乎有点不稳定。您是否考虑过数组的用户如何知道您在哪个索引中构建了哪种类型的Tile
?您是否考虑过数组中的所有对象必须具有相同的大小和对齐要求?编译器无法强制实施这些注意事项。
如果您事先知道可能的磁贴类型列表,我建议您使用:
// let Tile1, Tile2, Tile3 be the possible types
std::vector<std::variant<Tile1,Tile2,Tile3>>
如果无法约束类型列表,则可以使用:
std::vector<std::any>