首页 > 解决方案 > 指向类类型数组和带有 new 的构造函数的指针

问题描述

所以我正在编写一个类模板,我的类包含一个指向包含类类型实例的数组的指针。我的问题是我班级的构造函数。在我的构造函数中使用 new 关键字时,它无法正常工作。问题是当我在构造函数中使用 new 时没有创建我的数组。(就像它总是一个空指针而不是一个包含 Node 类实例的数组)我还应该说没有任何错误。这是我的代码。

#include <iostream>
#include <cstddef>

template <typename V>
class Node {
private:
  V _data;
  unsigned short _size;
  Node<V>* _children;
public:
  Node();
  Node(V);
  Node(V, unsigned short);
  Node(const Node&); // copy constructor
  ~Node();
};

template <typename V>
Node<V>::Node()
  : _data(0), _size(0), _children(nullptr) {}

template <typename V>
Node<V>::Node(V data)
  : _data(data), _size(0),  _children(new Node<V>[_size]) {}

template <typename V>
Node<V>::Node(V data, unsigned short size)
  : _data(data), _size(size), _children(new Node<V>[_size]) {}

template <typename V>
Node<V>::Node (const Node& other)
  : _size(other._size), _data(other._data) {
  _children = new Node<V>[_size];
  for (unsigned short i = 0; i < _size; i++) 
    _children[i] = other._children[i];
}

template <typename V>
Node<V>::~Node() { delete[] _children; }

int main () {
  Node<int> n1;
  Node<char> n2('A');
  Node<char> n3('B', 5);
  return 0;
}

感谢高级。

标签: c++arrayspointerstemplatesconstructor

解决方案


我已将您的代码复制到 Visual Studio 2017 CE 中,并将其放在它自己的头文件中。当我尝试从您的问题中编译代码时,Visual Studio 给了我这个编译器错误:

1>------ Build started: Project: StackOverflow, Configuration: Debug Win32 ------
1>main.cpp
1>c:\users\...\container.h(41): error C2039: '{dtor}': is not a member of 'Node<V>'
1>c:\users\...\container.h(41): error C2447: '{': missing function header (old-style formal list?)
1>Done building project "StackOverflow.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

为了修复这个编译器错误,我必须在类本身中添加declaration你的。dtordeclaration

template <typename V>
class Node {
//... previous code
public: 
    ~Node();
};

这使我能够编译、构建和运行代码,最终我得到了一个0. 在我看来,从语法或编译的角度来看,这段代码没有任何其他问题,但这并不意味着在正确性、效率或内存泄漏、悬空指针等方面没有任何问题。 ..


编辑


在处理此代码一段时间后,我注意到您现有代码存在一些问题:

您声明了这两个构造函数:

Node(V);
Node(V, unsigned short);

你让他们像这样定义:

template <typename V>
Node<V>::Node(V data)
: _data(data), _size(0), _children(new Node<V>[_size]) {}

template <typename V>
Node<V>::Node(V data, unsigned short size)
: _data(data), _size(size), _children(new Node<V>[_size]) {}

两者之间的唯一区别是大小的大小0,否则它们似乎做完全相同的事情。在第一种情况下,anint data[0]给了你什么?或者arraywith0元素会给你什么?

另一个问题涉及成员变量的使用。您使用的前缀_是糟糕的代码设计,因为它们是为语言和编译器或其他东西保留的。如果要区分成员变量和非成员变量。我喜欢改用后置修复_。示例:int non_member_varaible;int member_variable_;


为了清理您的代码,我删除了多个或冗余构造函数的额外依赖项。我还将它们保存在类声明中,因为这是一个类模板。我声明dtor为默认值。我还通过使用and删除了newand的使用。我还添加了一些辅助功能来检索大小和数据。我也没有对复制构造函数做任何事情,并且完全省略了它,因为一旦你的类可以运行,这应该是微不足道的。deletestd::vectorstd::shared_ptr

如果您在编译时确切地知道数组的大小,您可以交换std::vectorstd::array稍微修改代码。如果您希望此类拥有对象的唯一所有权,您可以通过一些细微的修改来std::shared_ptr替换。std::unique_ptr

出于演示目的,我选择std::vector<std::shared_ptr<Node>>用作内部容器。

也不是尝试向构造函数添加多个节点;我删除了那个依赖,只是把它变成了一个允许你在运行时添加节点的函数。如果在实例化该类时需要向该类添加多个节点,那么我建议使用variadic template constructor. 可变参数构造函数还可以让您能够将任何 Node 类型添加到容器中,只需对代码稍作修改。


这是我想出的:

容器2.h

#pragma once

#include <vector>
#include <memory>

template <typename V>
class Node {
private:
    V data_;
    std::vector<std::shared_ptr<Node>> children_;
public:
    Node() : data_{ 0 } {}
    explicit Node(V data) : data_{ data } {}

    void add_node(V data) {
        auto p = std::make_shared<Node<V>>(Node(data));
        children_.push_back(p);
    }

    ~Node() = default;

    const size_t size() const { return children_.size(); }
    const V data() const { return data_; }
    // no bounds checking just for demonstration purposes.
    const V data(unsigned index) { return children_[index]->data_; }
};

主文件

#include <iostream>

//#include "Container.h"
#include "container2.h"

int main() {
    try {
        Node<int> n1;
        Node<char> n2('A');
        Node<char> n3('B');
        n3.add_node('C');
        n3.add_node('E');

        std::cout << n3.size() << '\n';
        std::cout << n3.data(1) << '\n';

    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

输出

2
E

并且代码以退出代码退出0


推荐阅读