【问题标题】:How do I pass an array to a constructor?如何将数组传递给构造函数?
【发布时间】:2012-03-14 16:16:01
【问题描述】:

我想将数组传递给构造函数,但只传递了第一个值——其余的看起来像垃圾。

这是我正在研究的简化版本:

#include <iostream>

class board
{
    public:
        int state[64];
        board(int arr[])
        {
            *state = *arr;
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << state[x + y*8] << " ";
        std::cout << "\n";
    }
}

int main()
{
    int test[64] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}

有人可以解释为什么这不起作用以及如何正确传递数组吗?另外,我不想复制数组。 (而且我真的必须将代码的每一行缩进 4 个空格吗?这很乏味。)

【问题讨论】:

  • int (arr&)[64] 是你的数组的类型,数组不能被复制。最容易使用 std::array
  • 关于缩进,IDE通常会为你做这个。
  • 关于缩进——你不需要为每一行单独手动做。突出显示代码并按下编辑框上方的按钮,上面有一对大括号 - {} -。
  • @Default:是的,我意识到我只需要进入我的 IDE,全选,点击选项卡,然后就可以为这个网站格式化了。傻我。
  • @Michael Burr:谢谢。下次我试试那个方法。

标签: c++ arrays visual-c++ constructor


【解决方案1】:

在这种情况下,最好使用对数组的引用:

class board
{
    int (&state)[64];

public:
    board(int (&arr)[64]) 
        : state(arr)
    {}

    // initialize use a pointer to an array
    board(int (*p)[64]) 
        : state(*p)
    {}


    void print();
};

几个优点 - 无需复制数组,编译器将强制传入正确大小的数组。

缺点是,您初始化board 对象的数组需要至少在对象以及对对象外部数组所做的任何更改“反映”到对象的状态时才存在。但是如果你使用指向原始数组的指针也会出现这些缺点(基本上,只有复制数组才能消除这些缺点)。

另一个缺点是您不能使用指向数组元素的指针创建对象(如果数组大小未在参数的声明)。例如,如果数组是通过一个实际上是指针的函数参数传递的,并且您希望该函数能够创建一个引用该数组的 board 对象。

【讨论】:

  • 这行得通!谢谢你。这与 vvnraman 的解决方案相比如何?另外,你能解释一下: state(arr) 的作用吗?
  • state(arr) 初始化对作为构造函数参数传递的数组的引用。
  • 有人可以解释为什么数组绑定到test 并因此在超出范围时被销毁吗?如果两个变量指向同一个数组,为什么一个优先于另一个?
  • @Svad:引用只是它初始化对象的别名。引用对该对象的生命周期没有影响。如果您需要 board 对象的寿命比用于初始化它的数组长,那么我建议复制数组(您多次表示不想这样做)。另一种方法可能是使用shared_ptr 来管理阵列的生命周期;为此,您需要以某种方式在动态内存中创建数组。
  • 我不想复制,因为我打算制作非常大量的板对象,并且每次复制一个数组会很昂贵。所以看来我需要分配内存。 Avram 在另一个回复中提到了new。我也会调查shared_ptr。感谢您的解释和建议。
【解决方案2】:

尝试将数组传递给函数会导致传递指向数组第一个元素的指针。

你不能分配数组,像T[]这样的参数与T*是一样的。所以

*state = *arr;

正在取消引用指向statearr 的指针并将arr 的第一个元素分配给state 的第一个元素。

如果您想要将值从一个数组复制到另一个数组,您可以使用std::copy

std::copy(arr, arr + 64, state); // this assumes that the array size will
                                 // ALWAYS be 64

或者,您应该查看std::array&lt;int&gt;,它的行为与您假设数组的行为完全相同:

#include <array>
#include <algorithm>
#include <iostream> 

class board
{
    public:
        std::array<int, 64> state;

        board(const std::array<int, 64> arr) // or initialiser list : state(arr)
        {
            state = arr; // we can assign std::arrays
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << state[x + y*8] << " ";
        std::cout << "\n";
    }
}

int main()
{
    // using this array to initialise the std::array 'test' below
    int arr[] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    std::array<int, 64> test(std::begin(arr), std::end(arr));

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}

【讨论】:

  • 谢谢。这就解释了为什么我只得到第一个值。但是,我不想复制数组。我也不想使用向量。肯定有办法正确传递数组吗?
  • @SvadHisthana 不,你不能在 C++ 中按值传递一个真正的数组。你可以通过引用传递一个数组(这只有助于确定它的大小)但就是这样。
  • 我不打算按价值传递。 vvnraman 的解决方案就是我想要的。对不起,如果我没有更好地表达我的问题。感谢您的帮助!
  • @SethCarnegie:你已经颠倒了std::copy 的论点。他们是:std::copy(first, last, output).
  • @ChristianAmmer 谢谢,已修复。随意编辑我的帖子以解决类似的愚蠢错误。
【解决方案3】:
#include <iostream>

class board
{
    public:
        int * state;    //changed here, you can also use **state
        board(int *arr)               //changed here
        {
          state = arr;
        }
        void print();
};

void board::print()
{
    for (int y=0; y<8; y++)
    {
        for (int x=0; x<8; x++)
            std::cout << *(state + x + y*8) << " ";   //changed here
        std::cout << "\n";
    }
}

int main()
{
    int test[64] = {
        0, 1, 2, 3, 4, 5, 6, 7,
        1, 2, 3, 4, 5, 6, 7, 8,
        2, 3, 4, 5, 6, 7, 8, 9,
        3, 4, 5, 6, 7, 8, 9,10,
        4, 5, 6, 7, 8, 9,10,11,
        5, 6, 7, 8, 9,10,11,12,
        6, 7, 8, 9,10,11,12,13,
        7, 8, 9,10,11,12,13,14 };

    board b(test);
    b.print();

    std::cin.get();
    return 0;
}

或者您可以将其用作:

class board
{
    public:
        int state[64];
        board(int arr[])
        {
            for(int i=0;i<64;++i)
               state[i] = arr[i];
        }
        void print();
};

编辑 1: 稳定溶液

class board
    {
        public:
            int * state;    //changed here, you can also use **state
            board(int *arr)               //changed here
            {
              state = new int[64];
              for(int i=0;i<64;++i)
                   state[i] = arr[i];
            }
            void print();
    };

【讨论】:

  • 谢谢。虽然当我尝试编译您的第一个解决方案时,我收到第 6 行的错误:“只有静态 const 整数数据成员可以在类中初始化”vvnraman 的解决方案似乎正在工作。
  • 哪条线?我在构造函数之外找不到任何类成员的分配
  • 您的第一个示例无法编译。您不能使用 new() 初始化函数外部的成员。第二个问题是构造函数不会将数组的内容复制到分配的内存块中。它只是重新分配指针以指向传递给构造函数的数组。这将在您的示例代码中起作用,但在实际程序中,一旦数组测试超出范围,该内存就会变得无效。分配给状态的内存只会被泄露。
  • 哦,对不起,我没有看到它在构造函数之外。是的,您可以在构造函数中分配内存并复制数组内容以避免超出范围的问题。
【解决方案4】:

*arr 给出存储在 arr[0] 的值。在 c++ 中,数组的名称是指向数组中第一个元素的指针。

因此,当您执行 *state = *arr 时,会将 arr[0] 的值存储在变量 state 中。

现在,如果您想传递数组而不必显式复制每个元素,我建议您在调用的方法中创建另一个相同大小的数组,然后从调用者传递数组的名称,本质上:

methodWhereArrayisPassed(int *arrayName)
{
    int arrCopy[64];
    arrCopy = arrayName;

// Do more stuff here
}

methodWhichPassesArray()
{
    // do stuff here
    int arr[] = {
       0, 1, 2, 3, 4, 5, 6, 7,
       1, 2, 3, 4, 5, 6, 7, 8,
       2, 3, 4, 5, 6, 7, 8, 9,
       3, 4, 5, 6, 7, 8, 9,10,
       4, 5, 6, 7, 8, 9,10,11,
       5, 6, 7, 8, 9,10,11,12,
       6, 7, 8, 9,10,11,12,13,
       7, 8, 9,10,11,12,13,14 };

methodWhereArrayisPassed(arr);

// do stuff here
}

【讨论】:

  • 你不能分配像arrCopy = arrayName这样的数组
【解决方案5】:

数组的名称是其中第一个元素的地址。

因此*state = *arr 行将state[0] 设置为arr[0]

由于现在您已将state 定义为int state[64];,因此stateconst pointer 类型的int,其地址无法更改。

您可以将其更改为int *state;,然后state = arr 将起作用。

【讨论】:

  • 我尝试了你的建议并得到错误“表达式必须是状态的可修改左值”。
  • @SvadHisthana 我更新了答案,因为上一个中有一个错误。我没有注意到state 被声明为int [],这使它成为const pointer,因此它的地址不能更改。
  • @SvadHisthana 请记住,如果您这样做,state 将指向与arr 相同的数组,并且您对其中一个所做的任何更改都会对另一个进行。此外,如果 arr 超出范围,state 将指向已销毁的数组
  • 很高兴知道。那是期望的行为。但是,如果arr 超出范围,有什么方法可以保留state
  • 要保留state,你需要为其分配内存(state = new int[64];,然后将arr的内容复制到statestd::copy(arr, arr + 64, state);)。当然,如果你是要做到这一点,你必须实现Rule of Three,因为现在状态是一种资源。
【解决方案6】:

*state = *arr; 正在使用解引用,它返回指针地址处的值。

这与state[0] = *arr; 相同,因为*arrint

有关指针的信息,请参阅this article。请参阅尊重部分。

要解决这个问题,你想这样做:

for (int i = 0; i < 64; i++) state[i] = arr[i]

【讨论】:

  • 谢谢。但是,如果我尝试将 *state = *arr; 更改为 state = arr;,我的程序将无法编译,我收到一个状态错误“表达式必须是可修改的左值”。
  • @SvadHisthana 看最后一行,它会帮你搞定的
  • 谢谢,但我不想复制数组。 vvnraman 的解决方案似乎对我有用。
  • 但是在更大的程序中你可能会遇到范围问题。即,如果您的原始数组超出范围
  • 当心。在这种情况下,该解决方案将起作用。但是,test 是一个局部变量,函数返回后指向它的指针将无效。当然,当 main 返回时,程序就完成了,但是如果 test 不是来自 main,你可能会遇到麻烦。允许这种情况发生是一个糟糕的设计决策。
猜你喜欢
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多