如何避免在C++中使用新运算符
How to avoid using new operator in C++?
我有一个C++程序,它为文件中的所有字符创建霍夫曼代码。它工作得很好,但我想在不使用新运算符的情况下创建节点,因为我知道你不应该使用它。我尝试使用向量全局变量来保存节点,但这不起作用。
std::vector<Node> nodes;
Node* create_node(unsigned char value, unsigned long long counter, Node* left, Node* right) {
Node temp;
temp.m_value = value;
temp.m_counter = counter;
temp.m_left = left;
temp.m_right = right;
nodes.push_back(temp);
return &nodes[nodes.size() - 1];
}
编辑:我添加了更多的代码,我没有真正解释什么不起作用。问题是在generate_code()
中,它从未达到nullptr。我也尝试过使用Node而不是Node*,但同样的事情也发生了。
void generate_code(Node* current, std::string code, std::map<unsigned char, std::string>& char_codes) {
if (current == nullptr) {
return;
}
if (!current->m_left && !current->m_right) {
char_codes[current->m_value] = code;
}
generate_code(current->m_left, code + "0", char_codes);
generate_code(current->m_right, code + "1", char_codes);
}
void huffman(std::ifstream& file) {
std::unordered_map<unsigned char, ull> char_frequency;
load_data(file, char_frequency);
std::priority_queue<Node*, std::vector<Node*>, Comparator> queue;
for (auto& node : char_frequency) {
queue.push(create_node(node.first, node.second, nullptr, nullptr));
}
while (queue.size() != 1) {
Node* left = queue.top();
queue.pop();
Node* right = queue.top();
queue.pop();
auto counter = left->m_counter + right->m_counter;
queue.push(create_node(' ', counter, left, right));
}
std::map<unsigned char, std::string> char_codes;
Node* root = queue.top();
generate_code(root, "", char_codes);
for (auto& i : char_codes) {
std::cout << +i.first << ": " << i.second << "n";
}
}
一般的答案当然是使用智能指针,比如std::shared_ptr<Node>
也就是说,使用常规指针并没有那么糟糕,尤其是当您将所有指针都隐藏在外部时。我不会同意";不应该使用CCD_ 3";,更像";你应该意识到,如果你这样做了,你必须确保不会造成内存泄漏;。
在任何情况下,对于像您这样的操作,尤其是使用向量,您根本不需要实际的指针。只需为矢量存储一个索引,并用int
替换每次出现的Node*
,有点像:
class Node
{
public:
// constructors and accessors
private:
ValueType value;
int index_left;
int index_right;
}
我在这里使用了一个带符号的整数作为索引,以便为不存在的引用存储-1,类似于null指针
请注意,只有在矢量中没有任何内容被擦除的情况下,这才有效,至少在所有内容都被销毁之前不会。如果灵活性是关键,你需要某种指针
还要注意,不应该将向量作为全局变量。相反,有一个包装类,其中Node
是一个内部类,有点像这样:
class Tree
{
public:
class Node
{
...
};
// some methods here
private:
vector<Node> nodes;
}
使用这样的方法,可以更好地封装Node
类。CCD_ 8最有可能是CCD_。每个Node
将存储对其所属的Tree
的引用
另一种可能性是使向量成为Node
的静态成员,但我建议不要这样做。如果向量是Node
的静态成员或全局对象,在这两种情况下,您创建的所有树都在一个大容器中,这意味着当您不再需要它们时,您无法从其中一个容器中释放内存
虽然这在技术上不会是内存泄漏,但在实践中,它可以很容易地作为一个内存泄漏工作
另一方面,如果它存储为Tree
对象的成员,则一旦删除该对象,内存就会自动释放。
但我想在不使用新运算符的情况下创建节点,因为我知道你不应该使用它。
不鼓励直接使用new
的原因是所有权的语义(即谁负责相应的delete
(不清楚。
c++标准库为此提供了动态内存管理实用程序,尤其是智能指针。
所以我认为您的创建函数应该如下所示:
std::unique_ptr<Node> create_node(unsigned char value, unsigned long long counter, Node* left, Node* right) {
std::unique_ptr<Node> temp = std::make_unique<Node>();
temp->m_value = value;
temp->m_counter = counter;
temp->m_left = left;
temp->m_right = right;
return temp;
}
通过这种方式,很明显,调用者拥有新创建的Node
实例的所有权。
- 为什么比较运算符如此快速
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 使用算术运算符时如何避免从 char 到 int 的隐式转换
- 删除全局隐式函数 - 避免使用不明确的运算符
- 如何避免强制转换运算符 () 和访问运算符 [] 冲突?
- 避免对模板运算符过载的隐式参数转换
- C++ 避免代码重复运算符重载
- 如何避免重载赋值运算符将右值转换为左值
- 避免使用"运算符<<推迟"child"对象构造
- 避免在C++中强制转换运算符参数
- 调用派生类的函数调用运算符时避免使用指针
- 避免在数组订阅运算符中悬而未决的引用
- 如何避免忘记在子类中定义运算符==
- 避免基于模板运算符的存在编译某些行
- 如何使用具有模板转换运算符的非模板代理对象来避免指定boost::变体的类型
- 避免运算符>>在空格处中断输入
- 避免在复制构造函数和运算符=中重复相同的代码
- 为什么要避免C++中的后缀运算符
- 避免代码重复的最佳方法,定义比较运算符"<,<=,>,>=,==,!=",但要考虑NaN?
- 避免派生类的赋值运算符中的重复