Указатель на массив типа класса и конструктор с новым - PullRequest
0 голосов
/ 26 октября 2019

Итак, я пишу шаблон класса, и мой класс содержит указатель на массив, который содержит экземпляр типа класса. Моя проблема с конструктором моего класса. Когда в моем конструкторе я использую ключевое слово 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;
}

Спасибо в объявлении.

1 Ответ

0 голосов
/ 26 октября 2019

Я скопировал ваш код в 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 вашего dtor в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]? Или что дает array с 0 элементами?

Другая проблема касается использования ваших переменных-членов. Вы используете префикс _, который плохой дизайн кода, потому что они зарезервированы для языка и компилятора или других вещей. Если вы хотите различать переменную-член и не-член. Мне нравится использовать вместо этого пост-исправление _. Примеры: int non_member_varaible; и int member_variable_;.


Чтобы очистить ваш код, я удалил лишние зависимости нескольких или избыточных конструкторов. Я также держал их в объявлении класса, так как это шаблон класса. Я объявил dtor по умолчанию. Я также удалил использование new и delete, используя std::vector и std::shared_ptr. Я также добавил некоторые вспомогательные функции для получения размера и данных. Я также ничего не делал с конструктором копирования и опускал это полностью, так как это должно быть тривиально после того, как ваш класс будет работать.

Если вы точно знаете размер массива во время компиляции, вы можете обменяться std::vector с std::array и немного измените код. Если вы хотите, чтобы этот класс имел единоличное владение объектами, вы можете заменить std::shared_ptr на std::unique_ptr с небольшими изменениями.

В демонстрационных целях я выберу std::vector<std::shared_ptr<Node>> в качестве внутреннего контейнера.

Также вместо попытки добавить несколько узлов в конструктор;Я удалил эту зависимость и просто превратил ее в функцию, которая позволяет вам добавлять узлы во время выполнения. Если вам нужно добавить несколько узлов в этот класс, когда он создается, я бы предложил использовать variadic template constructor. Конструктор variadic также позволит вам добавить любой тип узла в контейнер с небольшими изменениями в коде.


Вот что я придумала:

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

main.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!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...