带有std字符串参数的模板类在使用本地数组作为存储时给出分段错误

问题描述 投票:1回答:2

这里是程序


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的事情。

提前感谢。

c++ list templates stl
2个回答
1
投票

您对未初始化的内存进行操作。尤其是您尝试实现自己的内存管理,这将在99%的实现中失败。

您可以在创建的类中简单地使用newdelete,而不再担心内存。

#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
投票

您告诉编译器将数组storage视为Node结构。但是storage中的数据未进行任何初始化,其内容为indeterminate,并且以任何方式使用它会导致undefined behavior

更具体地说,“结构”的成员未构造或初始化,因此尝试将成员data用于任何复杂的事情(如您的情况)很可能导致崩溃。

简单的解决方案是使用placement new

head = new (storage) Node;

请注意,在放置new后您不能delete该对象,您需要显式调用析构函数

head->~Node();
© www.soinside.com 2019 - 2024. All rights reserved.