【问题标题】:Problem with malloc and memcpy in array class数组类中的 malloc 和 memcpy 问题
【发布时间】:2021-04-09 11:43:05
【问题描述】:

我已经开始为 List 类编写一些代码,但我迷路了。我的 Arduino 项目需要它——我不能使用 STL。

这是代码。

#include <iostream>
    
template <typename T>
class List
{
public:
    List<typename T>()
    {
        m_Count = 0;
        m_Data = nullptr;
    }
    
    ~List()
    {
        free(m_Data);
    }
    
    void Push(const T& element)
    {
        m_Count++;
        T* alloc = (T*)malloc(size_t(sizeof(T) * m_Count));
        memcpy(alloc, m_Data, m_Count * sizeof(T));
        *(m_Data + sizeof(T) * (m_Count - 1)) = element;
    }
    
    T* operator [](unsigned int x) const
    {
        return (m_Data + x * sizeof(T));
    }
    
private:
    T* m_Data;
    uint64_t m_Count;
    
};
    
struct Vertex
{
    int x;
    int y;
};
    
int main()
{
    List<Vertex> list;
    list.Push({ 0, 1 });
    list.Push({ 2, 3 });
    list.Push({ 4, 5 });
    
    std::cout << list[0]->x << list[1]->x << list[2]->x;
}

问题出在Push方法的某个地方:当我调用memcpy时,程序触发了编译器断点。

【问题讨论】:

  • 为什么在 C++ 程序中使用malloc?其次,如果T 类型不可轻松复制,T* alloc = (T*)malloc(size_t(sizeof(T) * m_Count)); 将无法工作。如果您要创建自己的课程,请使用 new[]delete[]
  • 感谢您的回复。还有一个问题 - 在这种情况下我该如何使用 memcpy?
  • 首先开始使用new[]。其次,m_Data 新分配的内存分配在哪里?仔细查看您的代码,您会发现这并没有完成。
  • 为什么不应该使用 malloc 的问题是 malloc 不会创建对象。如果类型T 需要正确构造,malloc 对调用构造函数一无所知。因此,您现在调用malloc 的那行只分配了一堆字节,仅此而已。您现在有一堆字节不代表 TT 的数组应该代表什么。
  • Push() 中对memcpy() 的调用具有未定义的行为,因为m_Count 最初表示元素的数量,它会递增,然后memcpy() 会比现有元素多复制一个元素在原始缓冲区中。

标签: c++ malloc stdvector memcpy


【解决方案1】:

本质问题在*(m_Data + sizeof(T) * (m_Count - 1)) = element;这一行。在这里,您尝试将给定的 element 复制到 old(即预先存在的)m_Data 数组中;这将是第一次调用 Push 函数时的 nullptr(并且每隔一次就有一个元素太小)

因此,您需要首先释放旧数据(使用free(m_Data)),然后将新分配的内存分配给该指针(m_Data = alloc),然后才将element复制到该数组的最后一个元素。

但是,正如其他人所说,您为什么在 C++ 中使用mallocfree?下面的代码用new[]delete[] 替换了这些调用(尽管如果可能的话,使用std::vector 可能会更容易/更好/更安全)。

#include <iostream>

template <typename T>
class List {
public:
    List<T>() { // Don't need "typename" here!
        m_Count = 0;
        m_Data = nullptr;
    }
    ~List() {
        delete[] m_Data;
    }
    void Push(const T& element) {
        m_Count++;
        T* alloc = new T[m_Count];
        for (uint64_t i = 0; i < m_Count - 1; ++i) alloc[i] = m_Data[i]; // Copy old data (if any)
        delete[] m_Data; // Release old data
        m_Data = alloc; // Assign newly-allocated memory to m_Data
        m_Data[m_Count - 1] = element; // Why use pointer arithmetic when you have the [] operator?
    }
    T* operator [](unsigned int x) const {
        return &m_Data[x];
    }

private:
    T* m_Data;
    uint64_t m_Count;

};

struct Vertex {
    int x;
    int y;
};

int main()
{
    List<Vertex> list;
    list.Push({ 0, 1 });
    list.Push({ 2, 3 });
    list.Push({ 4, 5 });
    std::cout << list[0]->x << list[1]->x << list[2]->x << std::endl;
    std::cout << list[0]->y << list[1]->y << list[2]->y << std::endl;
    return 0;
}

我对您的代码进行了其他一些“小改进”(您的operator [] 看起来非常可疑,因为在进行指针运算时会固有地考虑指向对象的大小);还有其他可以制作,但恕我直言,与您发布的代码相差太远。


实际上,它总是在您的代码中为nullptr,因为您永远不会为它分配任何其他内容。

【讨论】:

  • 非常感谢您的详细回答。我从未真正使用过 malloc 函数,所以我不知道如何正确使用它。
猜你喜欢
  • 2023-04-07
  • 1970-01-01
  • 2021-10-20
  • 2014-03-10
  • 1970-01-01
  • 2018-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多