我最近一直在重新学习C++,因为我开发了一个游戏在虚幻引擎。自从我接触C++大约3年了,从那以后我一直在使用Java。
由于java和c++之间的差异,我已经可以看出,对于类似的概念,有不同的最佳实践。
我有两个这样的方法。
void UMarchingSquares::Generate(std::map<Vector2, int> automata) {
std::map<Vector2,ControlNode*> controlNodes = getControlNodes(automata);
}
std::map<Vector2,ControlNode*> UMarchingSquares::getControlNodes(std::map<Vector2, int> automata) {
std::map<Vector2,ControlNode*> controlNodes = std::map<Vector2, ControlNode*>();
for(pair<Vector2,int> pair : automata) {
Vector2 pos = pair.first;
ControlNode node = ControlNode(pos,pair.second);
controlNodes[pos] = &node;
}
return controlNodes;
}我可能打破了几个不同的C++最佳实践,但有一个,我真的需要澄清一个特定的领域。
我正在getControlNodes()方法的for loop中初始化for loop对象。我现在知道这样做是不好的,因为我正在存储一个指向局部变量的指针,然后每个循环迭代都会超出范围。我倾向于存储指针,而不是实际的Control节点(尽管我可能会确信不是这样,因为Control node持有位置2浮点数、物质1整数和其他两个同时具有位置和材质的对象)。
创建非局部变量指针的最佳方法是什么?我知道我可以只使用"new ControlNode()",但据我所知,这是一个相当昂贵的调用,并且需要清理(这可能也很昂贵)。我将相当频繁地调用代码的这一部分,所以我希望它是高效的。
谢谢!
发布于 2020-09-12 07:22:37
在过去的几年里,C++改变了很多,以使使用它的人的生活变得更容易。
查看您的代码,它提出了许多问题:
为什么在for-循环中,映射的值是指向的原始指针,而不是指向ControlNode的ControlNode或
auto可以帮助您在这里拥有更少的副本。
既然你的问题是关于第一个问题,我就忽略第二个问题。
从这个角度来看,您有三种修复代码的方法:
std::map<Vector2,ControlNode> getControlNodes(std::map<Vector2, int> automata) {
auto controlNodes = std::map<Vector2, ControlNode>{};
for(auto &&pair : automata) {
auto &&pos = pair.first;
auto node = ControlNode(pos,pair.second);
controlNodes[pos] = std::move(node);
}
return controlNodes;
}在这段代码中,您可以看到*已经从映射中删除。这意味着ControlNode的所有权被移动而不是映射。(还请注意std::move)这类似于将int存储在作为参数输入的映射中。
但是,如果您需要内存分配,因为您将在其中移动,并且地址需要稳定,那么std::unique_ptr是一个很好的解决方案。
std::map<Vector2,std::unique_ptr<ControlNode>> getControlNodes(std::map<Vector2, int> automata) {
auto controlNodes = std::map<Vector2, std::unique_ptr<ControlNode>>{};
for(auto &&pair : automata) {
auto &&pos = pair.first;
auto node = std::make_unique<ControlNode>(pos,pair.second);
controlNodes[pos] = std::move(node);
}
return controlNodes;
}如您所见,这段代码非常类似于前面的代码,我已经替换了映射中的类型,并将ControlNode的构造更改为std::make_unique。因此,您有一个包含对所分配内存的所有权的unique_ptr (只要您拥有unique_ptr,一切都是有效的)。
第三种解决方案只能在不能更改签名的情况下使用,并且在C++中被认为是错误的做法,因为它通过原始指针传递所有权。现在,调用方负责显式地清理内存,因为C++没有垃圾收集。
std::map<Vector2,ControlNode*> getControlNodes(std::map<Vector2, int> automata) {
auto controlNodes = std::map<Vector2, ControlNode*>{};
for(auto &&pair : automata) {
auto &&pos = pair.first;
auto node = new ControlNode(pos,pair.second);
controlNodes[pos] = node;
}
return controlNodes;
}PS:我在代码中添加了一些auto,以使代码段之间的更改最小化。
发布于 2020-09-12 06:51:07
使用控制节点的向量进行存储。当您需要一个新的控制节点时,将一个附加到该向量中。不要使用指针,而是使用指向该向量的迭代器。确保预先在该向量中预留了足够的插槽,否则迭代器将失效。
https://stackoverflow.com/questions/63856642
复制相似问题