【问题标题】:dynamic memory allocation to a struct type [duplicate]结构类型的动态内存分配[重复]
【发布时间】:2018-11-14 06:12:40
【问题描述】:

我正在尝试为结构动态分配内存,但在动态分配内存时出现错误

#include <string>

using namespace std;

#define MAX_GRADES 5

typedef struct _Student
{
    string id;
    string name;
    double grades[MAX_GRADES];
    double average;
}Student;

Student *update_list;

int main()
{
    Student *n = (*Student) malloc(sizeof(n));
    return 0;
}
main.cpp: In function ‘int main()’:
main.cpp:26:24: error: expected primary-expression before ‘)’ token
  Student *n = (*Student) malloc(sizeof(Student));
                        ^

【问题讨论】:

  • 重要提示:std::string 是一个相当复杂的类。仅当其众多构造函数中的至少一个成功初始化该类时,它才有效。 malloc 是一个 C 函数。 C 不知道构造函数是什么,因此没有运行 string 构造函数。这会留下idname 定时炸弹等待炸毁你的程序。不要 malloc 一个 C++ 类,除非你知道该类是一个 POD type 或者在使用前将使用 placement new

标签: c++


【解决方案1】:

TL;DR 版本

使用

Student *n = new Student;

而不是

Student *n = (*Student) malloc(sizeof(n));

说明

这是笔误

Student *n = (*Student) malloc(sizeof(n));
              ^ wrong side.

你想要

Student *n = (Student*) malloc(sizeof(n));
                     ^ needs to be here.

这将编译。通常我会发表评论并投票关闭,但是您会在运行时发现此解决方案有两个问题。

  1. n 是一个指针。 sizeof(n) 将给出一个指针的大小,它保证比 string 短(除非 string 的实现非常棒并且做的事情我什至无法想象)。如果下一点没有使该点无用,您可能希望sizeof(*n) 获得Student 的大小。
  2. std::string 是一个相当复杂的类。仅当其众多构造函数中的至少一个成功初始化该类时,它才有效。 malloc 是一个 C 函数。 C 不知道构造函数是什么,因此没有运行 string 构造函数。这会留下idname 定时炸弹等待炸毁你的程序。不要 malloc C++ 类,除非您知道该类是 POD type 或在使用前将使用 placement new

在此处使用new 或根本不动态分配。

【讨论】:

    【解决方案2】:

    学生*n = (*学生) malloc(sizeof(n));

    (*Student) 不是类型,你想要(Student*)。此外,sizeof n 给出了系统上指针的大小,而不是一个或多个 Students 所需的大小。正确方法:

    Student *n = (Student*) malloc(sizeof(*n));
    

    但是,正如 user4581301 的回答中所指出的,您的 Student 不是 POD,因此您必须使用 new 来确保正在调用构造函数:

    Student *n = new Student;
    

    或者,如果您想要多个Student

    Student *n = new Student[42];
    

    请记住,使用new 分配的所有内存必须使用delete 释放,使用new[]delete[] 分配的所有内存。

    但是使用原始拥有指针被认为是不好的做法,应该避免使用智能指针,如 std::unique_ptr&lt;&gt;std::shared_ptr&lt;&gt; 或容器:

    C++ 方式将使用std::vector&lt;Student&gt;
    此外,在 C++ 中没有理由将 typedef 用于 structure。

    【讨论】:

    • 实际上使用malloc 为问题中的对象分配内存是不正确的,其中包含string。请参阅讨论stackoverflow.com/questions/40434360/… 改用new
    • @francesco 哦,我错过了strings。假设它是一个 POD:/
    【解决方案3】:

    你的代码有三个错误:

    • malloc 之前的转换应该是(Student *):这是n 的正确类型,即指向Student 的指针。
    • 要分配的大小是sizeof(Student)sizeof(n) 会给你一个指针的大小,很可能对于Student 来说太小了。
    • 最重要的是:永远不要使用malloc 为包含string 之类的复杂对象的结构分配内存。您必须改用new,请参阅讨论here

    正确的代码是

    #include <string>
    
    using namespace std;
    
    #define MAX_GRADES 5
    
    struct Student
    {
        string id;
        string name;
        double grades[MAX_GRADES];
        double average;
    };
    
    Student *update_list;
    
    int main()
    {
        Student *n = new Student;
    
        delete n;
        return 0;
    }
    

    我在末尾添加了delete n:不一定能正确运行代码,但最好不要忘记删除分配的内存。

    更好的是,与其使用#define 来固定数组grades 的大小,不如使用模板参数:这样MAX_GRADES 不会在以下所有代码中传播。最后,通常最好避免在标题部分使用using namespace std;。这是因为,如果您将 Student 的声明拆分到单独的头文件中,则包含此类头文件的每个代码文件都将“继承”using namespace std;,这可能会与其他包含的头文件发生冲突。

    总而言之,您的代码的更好版本是

    #include <string>
    
    template <unsigned int MAX_GRADES>
    struct Student
    {
        std::string id;
        std::string name;
        double grades[MAX_GRADES];
        double average;
    };
    
    Student<5> *update_list;
    
    int main()
    {
        Student<5> *n = new Student<5>;
    
        delete n;
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      问题出在这部分代码中:

      int main()
      {
         Student *n = (*Student) malloc(sizeof(n));
         return 0;
      }
      

      了解 '*' 运算符是 C++ 中的间接运算符将有助于识别问题。 https://msdn.microsoft.com/en-us/library/caaw7h5s.aspx

      您不是在尝试提取Student 结构的值,而是尝试键入从malloc 返回的转换void *。正确的做法是:

      Student *n = new Student(正确的 C++ 做事方式 - 使用 new 运算符)

      这将为您提供指向动态创建的Student 结构的指针。如果您打算创建Student 的动态数组,您可以:

      Student *n = new Student[5]

      根据您的使用情况,您可能需要考虑一种简单的 C++ STL 方式:std::vector&lt;Student&gt;std::list&lt;Student&gt;

      查找 C++ 中的 STL(标准模板库),您应该能够获得更多详细信息。

      【讨论】:

      • 您不能使用malloc 分配像Student 这样包含复杂类型string 的对象。请参阅讨论 stackoverflow.com/questions/40434360/… 您必须改用 new
      • 感谢您指出,已相应修改了我的答案。尽管malloc 在 C++ 中工作它不是正确的方法。它不会调用构造函数等。在这种情况下它可能仍然有效,因为它是一个简单的结构。但是,是的,您所说的是在 C++ 中遵循的好习惯
      • 要明确一点:在这种情况下,malloc not 起作用,因为这里的结构包含string。带有malloc 的代码将编译,但它不会正确调用string 的构造函数,从而为未定义的分段错误行为铺平了道路。
      • 未定义的行为确实是阴险的。我会跪下并赞美任何使用他们的神力使未初始化或未正确初始化的指针始终出现段错误的神。是的,segfault 是现代 CPU 上最有可能的结果,但不太可能的情况往往是微妙的,并且会对程序造成极难诊断的损坏。其中最糟糕的没有明显的损坏,并且似乎可以正常工作,直到它们在最糟糕的时间发生灾难性故障。
      【解决方案5】:

      如果你在c++中,如果可以使用“new”,则不要使用“malloc”分配内存:

      Student* student = new Student();
      

      除了分配空间,“new”还将调用结构的构造函数,这将允许初始化。语法也不易出错。

      您还会注意到我的变量命名。在我的示例中,我选择了“student”而不是“n”,因为它对读者更具描述性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-12
        • 1970-01-01
        • 1970-01-01
        • 2021-12-03
        • 1970-01-01
        • 1970-01-01
        • 2014-11-24
        • 2015-05-17
        相关资源
        最近更新 更多