【问题标题】:Pointer to an array of class type and constructor with new指向类类型数组和带有 new 的构造函数的指针
【发布时间】:2020-02-22 16:06:35
【问题描述】:

所以我正在编写一个类模板,我的类包含一个指向包含类类型实例的数组的指针。 我的问题是我班级的构造函数。 在我的构造函数中使用 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;
}

感谢您。

【问题讨论】:

  • 如何它不是“正常工作”?请编辑您的问题以包括会发生什么以及应该发生什么。如果您遇到构建错误,请包含构建输出的完整和完整的复制粘贴,并在您遇到错误的行中添加 cmets。也请花一些时间阅读how to ask good questions,以及this question checklist
  • 它可能无法解决问题,不管它是什么,但是不要使用Node&lt;V&gt;* 使用std::shared_ptrstd::unique_ptr
  • @Someprogrammerdude 我刚刚编辑了问题.... _children 属性指向节点的 5 个实例,我得到 _children 没有指向任何内容(nullptr)。我邀请你(如果可能的话)执行pythontutor.com 中的代码,看看我在说什么。
  • Node&lt;V&gt;::Node(V data): _size(0), _children(new Node&lt;V&gt;[_size]) {} 是有问题的,因为它本质上是调用new Node&lt;V&gt;[0]
  • @churill 那么我应该怎么做才能修复它??????任何建议

标签: c++ arrays pointers templates constructor


【解决方案1】:

我已将您的代码复制到 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 ==========

要修复此编译器错误,我必须将 dtordeclaration 添加到类的 declaration 本身中。

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,否则它们看起来完全相同。在第一种情况下,int data[0] 给了你什么?或者带有0 元素的array 会给您带来什么?

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


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

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

出于演示目的,我选择使用std::vector&lt;std::shared_ptr&lt;Node&gt;&gt; 作为内部容器。

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


这是我想出的:

container2.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_; }
};

ma​​in.cpp

#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的退出代码退出!

【讨论】:

  • 啊是的。当然。我忘了从我的原始代码中复制~Node()。但问题不在于~Node()。问题在于堆中的分配。我认为我的默认构造有问题,当我在其他构造中使用 new 时,它并没有真正分配任何内存。
  • 当我有更多的时间时,我可以尝试解决这个问题,为您提供使用智能指针的可能解决方案,这将有助于使生活更简单,并减少头痛和头发拉伤.管理自己的记忆是可能的,但它很乏味并且必须精确。您必须知道您的代码是否将负责内存清理,或者目标用户的代码是否将负责。此外,您还必须事先假设对象的寿命。正确管理内存是一门艺术,需要很多技巧才能正确有效地完成。
  • 我认为在这种情况下堆的问题之一是您将 _size 存储为类的成员,并且您试图使用它来定义有多少 array 元素.这必须是compile time constant
  • @Mohammadreza 但我希望有一个不使用内存库而只使用简单指针的解决方案。 学习如何使用内存和指针总是一件好事。当你了解了纠正内存处理有多难时,你就会意识到vector 智能指针和 STL 中的许多其他东西有多么有用
  • @GianPaolo 当然。问题是我这样做是为了一个大学项目。这门课程都是关于编程语言的基础知识(今年元编程和泛型编程和继承)。所以我真的很想有一个简单的类而不使用太多的库。但现在我发现使用 STL 库更好也更安全。
猜你喜欢
  • 2018-06-08
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2020-11-08
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
相关资源
最近更新 更多