класс шаблона с аргументом std string дает ошибку сегментации при использовании локального массива в качестве хранилища - PullRequest
1 голос
/ 08 ноября 2019

Вот программа


using namespace std;

template <typename T>
class Test
{
public:
   struct Node{
      T data;
      Node *next;
   };

   void setData(T data)
   {
      head = reinterpret_cast<Node*>(storage);
      head->data = data;
   }
private:
   unsigned char storage[2048];
   Node* head;
};

int main()
{
   Test<std::string> test;
   test.setData("Hello");
   return 0;
}

Вышеуказанная программа компилируется и также отлично работает, когда аргумент имеет тип int. Но когда я устанавливаю аргумент как std :: string, он падает на - head-> data = data;

Это то, что я должен явно позаботиться о std :: string.

Спасибо взаранее.

Ответы [ 2 ]

1 голос
/ 08 ноября 2019

Вы работаете с неинициализированной памятью. Особенно вы пытаетесь реализовать собственное управление памятью, которое не удастся в 99% реализаций.

Вы можете просто использовать new и delete в своем созданном классе и больше не беспокоиться о памяти.

#include <string>

template <typename T>
struct Node {
    T data;
    Node *next;
};

template <typename T>
class Test
{
public:
    Test() {
        head = new Node<T>();
    }

    ~Test() {
        delete head; head = nullptr;
    }

    void setData(T data) {
        if (head = nullptr) {
            head->data = data;
        }
    }
private:
    Node<T>* head = nullptr;
};

int main() {
    Test<std::string> test_string;
    Test<int> test_int;
    test_string.setData("Hello");
    test_int.setData(1);
    return 0;
}

Важные примечания:

  • в конструкторе Test, память будет выделяться
  • для каждого new, должно бытьdelete. Поэтому обратите внимание на деструктор
  • для хорошей защитной реализации, всегда проверяйте, являются ли указатели nullptr
  • И для еще более лучшего стиля кода, ПОЖАЛУЙСТА, НЕ ИСПОЛЬЗУЙТЕ using namespace std;. Если вы сделаете это, вы open получите огромное пространство имен, которое может столкнуться с некоторыми именами ваших классов или функций. Эту ошибку почти невозможно найти.

отказ от ответственности: это работает на MSVC2017.

BONUS

Для более современных c++,Вы можете использовать std::unique_ptr.

#include <string>
#include <memory>

template <typename T>
struct Node {
    T data;
    Node *next;
};

template <typename T>
class Test
{
public:

    void setData(T data)
    {
        if (head = nullptr)
        {
            head->data = data;
        }
    }
private:
    std::unique_ptr<Node<T>> head = std::make_unique<Node<T>>();
};

int main()
{
    Test<std::string> test_string;
    Test<int> test_int;
    test_string.setData("Hello");
    test_int.setData(1);
    return 0;
}
1 голос
/ 08 ноября 2019

Вы указываете компилятору обрабатывать массив storage как Node структуру. Но данные в storage не инициализируются каким-либо образом, их содержимое является неопределенным , и любое его использование приводит к неопределенному поведению .

Более конкретночлены "структуры" не создаются и не инициализируются, поэтому попытка использовать элемент data для чего-либо сложного (как в вашем случае) очень вероятно приведет к сбоям.

Простое решение состоит в том, чтобыиспользуйте размещение new

head = new (storage) Node;

Обратите внимание, что после размещения new вы не можете delete объекта, вам нужно явно вызвать деструктор

head->~Node();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...