【问题标题】:Array as a data member数组作为数据成员
【发布时间】:2015-05-11 08:23:48
【问题描述】:

我想要一个包含数组作为数据成员的类。数组的大小是在构造过程中声明的。我知道在编译时需要知道数组的大小,但是有没有办法通过使用const int 来定义大小并随后使用构造函数初始化列表来解决这个问题?我不允许使用向量。这是我徒劳的尝试:

#include <iostream>

using namespace std;

class myArray {
    public:
        myArray(int size) : capacity(size) {}
    private:
        const int capacity;
        int a[capacity];
};

int main() {
    myArray ar(25); 
    return 0;     
}

它给出了以下错误: 'capacity' was not declared in this scope

【问题讨论】:

  • 这是一个挑战。我清楚地提到我们不允许使用向量。请不要问为什么,因为这是更好地理解数组的一种方式和挑战。
  • @paxdiablo 哦,那是我的错。
  • 我怀疑数组的大小必须或者是挑战所要求的,才能在运行时分配。这个问题有模板版本的答案吗?实际上,数组的容器通常在编译时通过设计确实知道它们的大小。在这些情况下,我们只需要以某种方式将大小暴露给类的接口,以便在类实例化时对其进行配置。我是模板新手,但我想将大小从构造函数参数移动到模板参数也应该有效。
  • 正如一些答案中所说,您必须使用某种指针。这样做的原因是在编译时必须知道对象的内存布局,并且数组数据成员是对象大小的一部分。也就是说,考虑具有成员数组 int a[1] int b[2] 的类 A 和 B。那么 sizeof(A) 将小于 sizeof(B)。此外,如果您想构造一个 myArray 对象数组,编译器需要这个静态大小。我希望这为限制提供一些合理性。指向数组的指针(或只是一个指针)是常量大小,sizeof(int *) 等。

标签: c++


【解决方案1】:

尝试使用指针代替

#include <iostream>
using namespace std;
class myArray {
public:
    myArray(int size) : capacity(size) {array = new int[capacity];}
    ~myArray() {delete [] array;}

private:
    const int capacity;
    int* array;
};

int main() {
    myArray ar(25); 
    return 0;     
}

别忘了在析构函数中释放。

【讨论】:

  • 是的,这似乎是一个流行的答案。你能解释一下原始代码有什么问题吗?
  • 在您的原始代码中,直到运行时才能获得数组的大小。数组要求在编译期间固定大小。
【解决方案2】:

以上所有答案都是“技术上正确的”,但没有一个真正显示智能指针的使用,这使得所有额外的内存管理都变得不必要。

class my_array
{
public:
   my_array (size_t sz)
     : arr {new int [sz]} {}

pirvate:
   std::unique_ptr <int[]> arr;
};

现在您不必关心(3 或 5)的规则,代码是正确的并且(大部分)异常安全。

【讨论】:

  • 不应该是std::unique_ptr&lt;int[]&gt;吗?两者的删除器不同。
【解决方案3】:

它可以与静态 const 一起使用,但您会丢失构造函数参数设置。您必须动态分配它才能工作:

class myArray {
    public:
        myArray(int size) : capacity(size) 
        {
            a = malloc(size * sizeof(int));
        }
        ~myArray() { free(a); }
    private:
        int capacity;
        int* a;
};

int main() {
    myArray ar(25); 
    return 0;     
}

虽然使用new [] 进行分配并使用delete [] 进行释放可能比 malloc 和 free 更 C++。

如某些 cmets 所述,如果您动态分配并且不使用自动资源管理对象,如 shared_ptrunique_ptr,则必须遵循 rule of three

【讨论】:

  • 是的,这似乎是一个流行的答案。你能解释一下原始代码有什么问题吗?
  • 我几乎会说从不在 C++ 代码中使用malloc/free,它是仅用于遗留支持的东西之一。它不会在内存不足时引发异常,因此除非您想要狡猾的程序,否则您必须自己管理。您还应该强制转换 malloc 返回值,以免编译器抱怨。
【解决方案4】:

原始类的问题在于它允许不同的值作为容量传入。因此,您不能以您想要的方式创建具有该值的数组。您只创建一个大小为 25 的实例没有区别,这是 程序的属性, 并且类本身不知道它只是以这种方式使用.


现在我不会质疑为什么你不能使用向量,但不使用语言/库的全部功能似乎很可惜。

但是,鉴于您的限制,您可以动态创建数组,而不是尝试创建固定数组:

#include <iostream>

using namespace std;

class myArray {
    public:
        myArray(int size) : capacity(size) {
            a = new int[capacity];
        }
        ~myArray() {
            delete[] a;
        }
        // Also need all those other things, mandated by the
        // rule of 3/5, to allow proper deep copy/move:
        // - copy constructor.
        // - copy assignment operator.
        // - move constructor (C++11).
        // - move assignment operator (C++11).

    private:
        const int capacity;
        int *a;
};

int main() {
    myArray ar1(25);
    myArray ar1(42);
    return 0;
}

【讨论】:

  • 谢谢。数组必须在堆上动态分配吗?
  • 复制myArray时会出现问题。 a 将被删除两次。
  • @fefe:是的。其目的只是展示将阵列转变为动态阵列所需的更改,而不是提供完整的、防弹的应用程序。我添加了 cmets 来指示应该完成的其他工作。
【解决方案5】:

通过将capacity 作为变量传入,您将拥有一个动态大小的数组(其大小仅在运行时才知道)。这意味着sizeof(myArray)对于编译器来说是未知的,这会导致问题。

相反,您需要存储一个指向数组的指针。

另一种(丑陋的)方法是使用放置策略,将数组放在结构/类的末尾,并将其大小固定为 1,如图所示here

【讨论】:

  • 嗯...就像在堆上分配数组一样?不错的建议。但是,您能否解释一下在我的实现中如何仅在运行时知道大小?我的意思是,大小是在创建对象时作为构造函数参数提供的。因此,与在运行时将大小作为控制台输入之类的操作相反,它已经众所周知。
  • 但您也可以拥有myArray ar2(25)。现在sizeof(ar) != sizeof(ar2)。数组成员的大小必须是恒定的。
  • 但是,ar2 完全是一个新实例。数组的大小在实例中是恒定的。
【解决方案6】:

constness 是不够的,因为您甚至可以取用户在程序执行期间提供的值,并将其设为const

int x;
std::cin >> x;
const int y = x;

这是不够的,因为数组维度必须在程序编译时知道

从历史上看,如果您要在声明时初始化 static const“变量”,那么这足以让编译器相信它可以将该值用于数组维度:

static const unsigned int N = 5;

因为不可能出错。

现在,我们有 constexpr 来明确说明这一点。

【讨论】:

    【解决方案7】:

    您可以使用模板非类型参数(仅适用于 C++)。看看这个页面和例子:

    https://www.ibm.com/docs/en/zos/2.1.0?topic=arguments-template-non-type.

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-24
    相关资源
    最近更新 更多