【问题标题】:c++ dynamic arrays in classc++类中的动态数组
【发布时间】:2018-09-11 19:19:34
【问题描述】:

我正在尝试在类中创建一个带有动态数组的示例,以便使用析构函数和复制构造函数。

该程序的想法如下。我有两个私有字段的类 Labtest。 ntest 一个整数,其中包含测试和值的数量,它是具有 ntest 元素的动态数组。

我添加了方法 add 将动态数组扩展一并将参数添加到最后一个位置。

我添加了一个友元函数 max,它返回动态数组的最大元素(通过值对象进行调用),以证明复制构造函数的必要性。

为了打印对象,我重载了

我添加了默认构造函数、析构函数、复制构造函数。

目前我写的代码是

#include<iostream>
using namespace std;

class Labtest {
public:
    Labtest();
    Labtest(const Labtest& a);
    ~Labtest();
    friend int max(Labtest a);
    friend ostream& operator <<(ostream& out, const Labtest& lab);
    void add_value(int a);
private:
    int ntests;
    int *values;
};

int main()
{
    Labtest chem;
    chem.add_value(10); chem.add_value(20);
    cout << chem;
    cout << "the maximum is " << max(chem) << endl;
    cout << chem;
    return 0;
}

Labtest::Labtest() : ntests(0), values(NULL)
{
}

Labtest::Labtest(const Labtest & a) : ntests(a.ntests)
{
    values = new int(ntests);
    for (int i = 0; i < ntests; i++)
        values[i] = a.values[i];
}

Labtest::~Labtest()
{
    ntests = 0;
    delete[] values;
}

void Labtest::add_value(int a)
{
    int *newvalues = new int(ntests+1);
    for (int i = 0; i < ntests; i++)
        newvalues[i] = values[i];
    newvalues[ntests] = a;
    delete[] values;
    values = newvalues;
    ntests++;
}

int max(Labtest a)
{
    int m = a.values[0];
    for (int i = 1; i < a.ntests; i++)
        if (m < a.values[i])
            m = a.values[i];
    return m;
}

ostream& operator <<(ostream & out, const Labtest& lab)
{
    for (int i = 0; i < lab.ntests; i++)
        out << lab.values[i] << " ";
    out << endl;
    return out;
}

我在 Visual Studio 中遇到堆外边界错误。即使我评论了对 max 函数的调用。

任何帮助将不胜感激!

【问题讨论】:

  • new int(10) 创建一个值为10 的数组。 new int[10] 创建一个包含 10 个 ints 的数组。
  • 您应该知道int max(Labtest a) 在每次调用时都会复制a。你应该改用const Labtest &amp; a
  • 你是对的!我不能相信这样的错误!!!此外,对于 a 的副本,每次 max 完成时,析构函数都会释放 a 的内存。对吗?
  • 是的,额外的副本在技术上不是问题。尽管了解何时通过引用传递很重要,但何时通过值而不是参数传递应该是const。在这种情况下,Labtest 仅包含 ints,并且可能永远不会包含太多值。但在实践中,不必要地复制容器是一个坏习惯。
  • 谢谢,我只是为了演示复制构造函数的需要。请回答以便给您投票。 :-)

标签: c++ copy-constructor dynamic-arrays


【解决方案1】:

当您分配数组时,您应该使用方括号而不是 [] 来执行 int *newvalues = new int[ntests+1];

【讨论】:

    【解决方案2】:

    new int(10) 生成一个值为 10 的 int 变量。new int[10] 生成一个包含 10 个 ints 的数组。从上下文来看,很明显您打算使用第二种形式。当您调用delete[] values;(因为values 不是数组)或访问第一种以外的任何元素时,使用第一种形式会导致未定义的行为。

    【讨论】:

      【解决方案3】:

      模板类 sdt::vector 只提供您需要的功能 - 无需您参与内存管理的细节。 但如果想练习内存管理,我应该提醒你 3 个注意事项:

      1. 数组 new 运算符的语法是 new type_spec[n] 而不是 new type_spec(n)。您使用的语法只是分配一个对象并用 n 初始化它。所以用数组删除操作符处理它会导致UB。

      2. 删除后使指针无效更安全。

      3. 在定义任何获取系统资源的类(本例中为堆内存)时,通常需要定义以下函数:

        复制构造函数。

        交换功能。

        移动构造函数,通常以交换的形式。

        就交换而言,移动/复制关联运算符或两者兼而有之。

        在交换方面的析构函数。

      否则 - 迟早 - 由于忘记隐式临时对象生成或其他语义,会违反 1 个或多个资源处理规则。并且会出现异常行为。

      【讨论】:

      • 你的第二点是错误的。删除后使指针无效根本不会使任何事情更安全。
      • 它至少可以防止双重删除。如果成为一种习惯,则触发 - 希望是 - 早期运行时内存异常,否则对已删除对象错误的静默引用可能会导致程序出错。还有更多,但我不能把它放在 char[600] 中。
      • 它无法防范最危险的双重删除形式,即当您的程序中有更多指向同一对象的指针时。也不能期望它会触发任何事情,因为取消引用 nullptr 无论如何都是未定义的行为。它所做的只是给你一种错误的安全感和消耗 CPU 周期:)
      • 我要给出一个完整的实现吗?这还不够,但至少可以做到这一点。顺便说一句,为什么有人要公开原始指针?关于null的情况;在多个 pc 平台上取消引用会引发内存异常。使用原始指针一直是在刀尖上行走;这就是为什么最好尽量减少操作并仅在析构函数中显式使用 delete 一次。
      • 如果只在析构函数中删除,那么设置指针为null就更没有意义了。析构函数完成后,没有人可以访问指针。我不是在争论原始指针,我只是认为在删除后设置指向nullptr 的指针不会使任何事情更安全。
      猜你喜欢
      • 2012-06-19
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2020-07-22
      • 1970-01-01
      • 2020-07-03
      • 1970-01-01
      相关资源
      最近更新 更多