动态分配一个对象数组

17 浏览
0 Comments

动态分配一个对象数组

我有一个包含动态分配数组的类,假设\n

class A
{
    int* myArray;
    A()
    {
        myArray = 0;
    }
    A(int size)
    {
        myArray = new int[size];
    }
    ~A()
    {
        // 根据MikeB的有益的风格批评,注意不需要检查是否为0。
        delete [] myArray;
    }
}

\n但现在我想创建一个动态分配的这些类的数组。这是我当前的代码:\n

A* arrayOfAs = new A[5];
for (int i = 0; i < 5; ++i)
{
    arrayOfAs[i] = A(3);
}

\n但这个代码出现了严重的问题。因为新创建的`A`对象(通过`A(3)`调用)在`for`循环迭代完成时被销毁,这意味着该`A`实例的内部`myArray`被`delete []`。\n所以我想我的语法一定是非常错误的?我猜有几种修复方法似乎过于繁琐,我希望能够避免:\n- 为`A`创建一个拷贝构造函数。\n- 使用`vector`和`vector`,这样就不用担心这些问题了。\n- 将`arrayOfAs`作为`A`对象的数组,改为作为`A*`指针的数组。\n我认为这只是一个初学者的问题,当尝试动态分配一个具有内部动态分配的数组时,实际上有一种语法是有效的。\n(另外,对于C++我已经有一段时间没有使用了,所以如果有风格上的批评,也请指出来。)\n更新供未来查看者参考:下面的所有答案都非常有帮助。Martin的答案被接受,因为有示例代码和有用的“四个法则”,但我真的建议阅读它们。有些是对错误的简洁陈述,有些则正确指出了为什么使用`vector`是一个好办法。

0
0 Comments

动态分配对象数组的问题出现的原因是,在A对象的构造函数中动态分配了另一个对象,并将指向该动态分配对象的指针存储在一个原始指针中。对于这种情况,必须定义自己的拷贝构造函数、赋值运算符和析构函数。编译器生成的这些函数将无法正确工作。这是“大三法则”的一个推论:具有析构函数、赋值运算符、拷贝构造函数中的任意一个的类通常需要这三个函数都存在。

你已经定义了自己的析构函数(并且提到了创建拷贝构造函数),但你需要定义其他两个“大三”中的函数。

另一种解决方法是将指向动态分配的int[]的指针存储在其他对象中,这个对象将为你处理这些事情。比如一个vector(正如你提到的)或者一个boost::shared_array<>。

为了充分利用RAII的优势,尽可能避免处理原始指针。

另外,你问到了其他风格的批评,一个小的建议是在删除原始指针时,不需要在调用delete之前检查0,delete会处理这种情况,什么也不做,所以你不需要在代码中加入这些检查。

有很多非常好的答案;我真的想将大多数答案,包括你的答案,作为“最佳答案”接受。非常感谢。还有对风格的批评。

这是“四法则”。它需要一个普通的构造函数。如果你不初始化指针,它们就会有随机值。

- 你是对的。我一直听说过“三法则”,因为构造函数被认为是“给定的”。但我认为明确地将其包括在规则中是更好的做法。

0
0 Comments

动态分配对象数组的问题一直存在,但是使用std::vector可以解决这个问题。下面是使用std::vector的示例代码:

typedef std::vector A;
typedef std::vector AS;

使用std::vector可以避免重新发明轮子,而且可以更多地专注于实现应用程序的特定功能。

0
0 Comments

动态分配对象数组的出现的原因是当对象包含原始指针时,需要遵循构造函数、析构函数、拷贝构造函数、赋值运算符、移动构造函数和移动赋值运算符的规则。如果未定义这些方法,编译器会生成默认版本,但在处理原始指针时,这些默认版本并不总是有用的。

其中,拷贝构造函数是最难正确实现的(如果要提供强异常保证),赋值运算符可以根据拷贝构造函数来定义,因为可以在内部使用拷贝并交换技术。

为了解决这个问题,可以考虑使用std::vector而不是指向整数数组的指针。std::vector易于使用和扩展,并且涵盖了与异常相关的所有问题。

在给定的问题中,使用new运算符动态分配了一个A类型的对象数组。在循环中,对数组的每个元素进行了赋值操作,但由于未定义赋值运算符,编译器生成的默认版本就被使用了。这导致了浅拷贝的问题,即两个对象都包含指向同一块内存的指针。当A(3)超出作用域后,它调用了delete []释放了其指针指向的内存,这导致数组中的其他对象现在包含指向已被系统回收的内存的指针。

为了正确处理包含指针的类,至少需要定义构造函数、析构函数、拷贝构造函数和赋值运算符。

关于异常问题的更多信息,请参考相关文章。

为什么将"raw"大写?这不是任何缩写,只是表示"raw"的意思,即未修改、未封装为智能指针或其他包装器。

"raw"被称为"scare quotes"。

移动赋值运算符为什么不返回任何值?因为这是一个错误。需要进行修复。

0