模板类和遍历的无效构造函数
Deafult constructor of template class and traversing
我有一个Node类和一个Tree类,在我的Tree类(这是一个m-ary树(中,我有一种方法可以对我的树进行有序遍历
所以问题是,当我调用这个方法时,我能够打印树的第一个分支,之后我会出现分段错误。我知道(通过调试(错误可能来自Node类的构造函数中的某个位置,或者我没有编写一个很好的遍历方法
这是我的代码。
节点.hpp
#ifndef NODE_HPP
#define NODE_HPP
#include <iostream>
#include <cstddef>
template <typename V, unsigned short N>
class Node {
private:
V _data;
Node<V, N>* _children[N];
template <typename U, unsigned short M>
friend std::ostream& operator<< (std::ostream&, const Node<U, M>&);
public:
Node();
Node(V);
Node(V, unsigned short);
Node(const Node&); // copy constructor
Node& operator= (Node&); // assignement by copy constructor
Node (Node&&); // transfer constructor
Node& operator= (Node&&); // assignement by transfer constructor
~Node() = default;
V getData() const;
Node<V, N>* getChildren();
void setChild(unsigned short, Node<V, N>*);
void delChild(unsigned short);
Node<V, N>* getChild(unsigned short);
};
template <typename V, unsigned short N>
Node<V, N>::Node()
: _data(0), _children(nullptr) {}
template <typename V, unsigned short N>
Node<V, N>::Node(V data)
: _data(data) {
for (unsigned short i = 0; i < N; i++)
_children[i] = NULL;
}
template <typename V, unsigned short N>
Node<V, N>::Node(V data, unsigned short size)
: _data(data) {
for (unsigned short i = 0; i < size; i++)
_children[i] = NULL;
}
template <typename V, unsigned short N>
Node<V, N>::Node (const Node& other)
: _data(other._data) {
// _children = other._children;
for (unsigned short i = 0; i < N; i++)
_children[i] = other._children[i];
}
template <typename V, unsigned short N>
Node<V, N>& Node<V, N>::operator= (Node& n){
if (&n != this) {
delete _children;
_data = n._data; _children = n._children;
n._data = 0; n._children = nullptr;
}
return *this;
}
template <typename V, unsigned short N>
Node<V, N>::Node (Node&& n){
_data = n._data; _children = n._children;
n._data = 0; n._children = nullptr;
}
template <typename V, unsigned short N>
Node<V, N>& Node<V, N>::operator= (Node&& n){
if (&n != this) {
delete _children;
_data = n._data; _children = n._children;
n._data = 0; n._children = nullptr;
}
return *this;
}
template <typename V, unsigned short N> // TO DO : move this to class scope ???
V Node<V, N>::getData() const {return _data;}
template <typename V, unsigned short N>
Node<V, N>* Node<V, N>::getChildren() {return *_children;}
template <typename V, unsigned short N>
void Node<V, N>::setChild(unsigned short index, Node<V, N>* childNode){
this->_children[index] = childNode;
}
template <typename V, unsigned short N>
void Node<V, N>::delChild(unsigned short index){
this->_children[index] = NULL;
}
template <typename V, unsigned short N>
Node<V, N>* Node<V, N>::getChild(unsigned short index){
return &this->_children[index];
}
template <typename V, unsigned short N>
std::ostream& operator<< (std::ostream& o, const Node<V, N>& node){
if (node._data) o << node._data ;
return o;
}
#endif
树.hpp
#ifndef TREE_HPP
#define TREE_HPP
#include <iostream>
#include <cstddef>
#include "node.hpp"
template <typename V, unsigned short N>
class Tree {
private:
Node<V, N>* _info;
public:
Tree();
Tree(Node<V, N>*);
Tree(V, unsigned short);
Tree(const Tree&) = delete; // copy constructor
Tree& operator= (const Tree&) = delete; // assignement by copy constructor
Tree (Tree&&); // transfer constructor
Tree& operator= (Tree&&); // assignement by transfer constructor
~Tree() {delete _info;}
Node<V, N>* info();
bool vide();
bool ins(unsigned short, Node<V, N>*);
bool del(unsigned short);
Node<V, N>* fils(unsigned short);
void inorderTraverse(Node<V, N>*);
};
template <typename V, unsigned short N>
Tree<V, N>::Tree()
: _info(nullptr) {}
template <typename V, unsigned short N>
Tree<V, N>::Tree(Node<V, N>* newNode)
: _info(newNode) {}
template <typename V, unsigned short N>
Tree<V, N>::Tree(V data, unsigned short size) {
Node<V, N>* node = new Node<V, N>(data, size);
_info = node;
}
template <typename V, unsigned short N>
Tree<V, N>::Tree(Tree&& t) {
_info = t._info;
t._info = nullptr;
}
template <typename V, unsigned short N>
Tree<V, N>& Tree<V, N>::operator= (Tree&& t) {
if (&t != this) {delete _info; _info = t._info; t._info = nullptr;}
return *this;
}
template <typename V, unsigned short N>
Node<V, N>* Tree<V, N>::info() { return _info;}
template <typename V, unsigned short N>
bool Tree<V, N>::vide() {
return true ? _info : false;
}
template <typename V, unsigned short N>
bool Tree<V, N>::ins(unsigned short index, Node<V, N>* node){
if (_info) {
_info->setChild(index, node);
return true;
}
return false;
}
template <typename V, unsigned short N>
bool Tree<V, N>::del(unsigned short index){
if (_info) {
_info->delChild(index);
return true;
}
return false;
}
template <typename V, unsigned short N>
Node<V, N>* Tree<V, N>::fils(unsigned short index){
return &_info->getChild(index);
}
template <typename V, unsigned short N>
void Tree<V, N>::inorderTraverse(Node<V, N>* node){
if (node->getData()){
std::cout << *node << "n";
for (unsigned short i = 0; i < N; i++) {
if (node->getChildren()[i].getData()){
inorderTraverse(&node->getChildren()[i]);
}
}
}
}
#endif
main.cpp
#include <iostream>
#include <cstddef>
#include "tree.hpp"
#include "node.hpp"
#define SIZE 5
int main() {
Node<char, SIZE> n1('A',SIZE);
Node<char, SIZE> n1_1('B',SIZE);
Node<char, SIZE> n1_2('C',SIZE);
Node<char, SIZE> n1_3('D',SIZE);
Node<char, SIZE> n1_1_1('E',SIZE);
Node<char, SIZE> n1_1_2('F',SIZE);
Node<char, SIZE> n1_1_1_1('G',SIZE);
Node<char, SIZE> n1_2_1('H',SIZE);
Node<char, SIZE> n1_2_1_1('I',SIZE);
Node<char, SIZE> n1_3_1('J',SIZE);
n1.setChild(0,&n1_1);
n1.setChild(1,&n1_2);
n1.setChild(2,&n1_3);
n1_1.setChild(0,&n1_1_1);
n1_1.setChild(1,&n1_1_2);
n1_1_1.setChild(0,&n1_1_1_1);
n1_2.setChild(0,&n1_2_1);
n1_2_1.setChild(0,&n1_2_1_1);
n1_3.setChild(0,&n1_3_1);
Tree<char, SIZE> t(&n1);
t.inorderTraverse(t.info());
return 0;
}
提前感谢您对的帮助
Node::getChildren()
返回*_children
,它是_children
数组中的第一个指针。然后调用node->getChildren()[i]
,它将i
添加到此指针。这恰好适用于第一个节点,因为您已经将所有节点并排放置在堆栈上,因此它会返回正确的节点。这是未定义的行为,在具有堆分配节点的真实代码中,这会很快崩溃。getChildren
应为:
template <typename V, unsigned short N>
Node<V, N>** Node<V, N>::getChildren() { return _children; }
那么你的呼叫代码将是:
if (node->getChildren()[i]->getData()) {
inorderTraverse(node->getChildren()[i]);
}
这将使我们回到由于取消引用空指针而导致崩溃的原始原因。这里的简单修复方法是只检查子项是否为空:
auto children = node->getChildren();
if (children[i] && children[i]->getData()) {
inorderTraverse(children[i]);
}
由于Tree
析构函数删除了堆栈分配的节点,您的代码现在将在退出时崩溃:
~Tree() { delete _info; }
如果要使用delete
,则需要使用new
创建所有节点,而不是在main
中堆栈分配。最好使用std::unique_ptr
或std::shared_ptr
,完全避免使用delete
。
相关文章:
- 错误: 无效使用非静态数据成员"应用程序::应用程序构造函数"
- 为什么构造函数的虚拟函数调用有时有效,但其他调用却无效
- 模板类和遍历的无效构造函数
- C ++回测问题:如何检查构造函数在假定失败时是否失败(给定输入的无效参数)
- static_cast 的 unique_ptr 无效 *,带有构造函数参数
- 瓦尔格林德:构造函数中大小为 1 的无效读取
- 编译器错过了无效的构造函数调用,并调用不存在的(或私有的)默认构造函数
- 汇编错误:调用基本型构造函数时无效的转换
- 移动构造函数是否使shared_from_this无效
- 将const char*传递到构造函数中,使得无效
- 调用不带参数的构造函数有效,使用参数则无效。为什么?
- 将成员枚举变量传递给类构造函数时出现无效的重定义错误
- 如何确保当无效字符串作为参数传递时posix_time_zone构造函数不会崩溃
- 构造函数中大小为 4 的写入无效
- 将数组传递给构造函数无效
- 无效的分配大小(在派生类复制构造函数中)
- 如何处理传递给构造函数的语法有效但逻辑无效的参数
- C++中的构造函数错误无效
- C++错误"无效的构造函数;您的意思可能是"帐户(常量帐户&)
- 无效地使用不完整的类型模板构造函数声明