C++ - 创建非局部变量指针的最佳方式
C++ - Best way to create a non-local variable pointer
我最近在 Unreal engine 开发游戏时重新学习 C++。接触C++已经快3年了,从那以后我主要用Java
由于 java 和 c++ 之间的差异,我已经知道对于相似的概念有不同的最佳实践。
我有2种这样的方法。
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
中初始化 ControlNode
对象。我现在知道这样做是不好的,因为我正在存储一个指向局部变量的指针,然后每次循环迭代都会超出范围。我宁愿存储指针而不是实际的控制节点(尽管我可能不这么认为,因为控制节点持有一个位置 [2 个浮点数],一个 material [1 个整数],以及两个其他对象都具有他们自己的位置和 material。)
创建非局部变量指针的最佳方法是什么?我知道我可以只使用“new ControlNode()
”,但据我所知,这最终是一个相当昂贵的调用,并且需要清理(这可能也很昂贵)。
我将相当频繁地调用这部分代码,所以我希望它是高效的。
谢谢!
使用控制节点向量进行存储。每当您需要一个新的控制节点时,将一个 1 添加到该向量。不要使用指针,而是使用指向该向量的迭代器。确保您预先在该向量中保留了足够的插槽,否则您的迭代器将失效。
C++ 在过去几年中发生了很大变化,使使用它的人的生活更轻松。
看了你的代码,提出了很多问题:
- 为什么你的映射值是指向 ControlNode 的原始指针,而不是按值或 unique_ptr 指向它的 ControlNode
- 在你的for-loop中,为什么要写显式的pair类型(它不同于迭代器),
auto
可以帮助你减少副本
因为你的问题是关于第一个,我会忽略第二个。
看到这里,您有 3 种修复代码的方法:
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 以尽量减少片段之间的更改。
我最近在 Unreal engine 开发游戏时重新学习 C++。接触C++已经快3年了,从那以后我主要用Java
由于 java 和 c++ 之间的差异,我已经知道对于相似的概念有不同的最佳实践。
我有2种这样的方法。
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
中初始化 ControlNode
对象。我现在知道这样做是不好的,因为我正在存储一个指向局部变量的指针,然后每次循环迭代都会超出范围。我宁愿存储指针而不是实际的控制节点(尽管我可能不这么认为,因为控制节点持有一个位置 [2 个浮点数],一个 material [1 个整数],以及两个其他对象都具有他们自己的位置和 material。)
创建非局部变量指针的最佳方法是什么?我知道我可以只使用“new ControlNode()
”,但据我所知,这最终是一个相当昂贵的调用,并且需要清理(这可能也很昂贵)。
我将相当频繁地调用这部分代码,所以我希望它是高效的。
谢谢!
使用控制节点向量进行存储。每当您需要一个新的控制节点时,将一个 1 添加到该向量。不要使用指针,而是使用指向该向量的迭代器。确保您预先在该向量中保留了足够的插槽,否则您的迭代器将失效。
C++ 在过去几年中发生了很大变化,使使用它的人的生活更轻松。
看了你的代码,提出了很多问题:
- 为什么你的映射值是指向 ControlNode 的原始指针,而不是按值或 unique_ptr 指向它的 ControlNode
- 在你的for-loop中,为什么要写显式的pair类型(它不同于迭代器),
auto
可以帮助你减少副本
因为你的问题是关于第一个,我会忽略第二个。
看到这里,您有 3 种修复代码的方法:
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 以尽量减少片段之间的更改。