C++:数组的构造函数/初始化器?

8
我熟悉C++的构造函数和初始化器:
class Foo {
   int x;
public:
   Foo(int _x) : x(_x) {}
};

Foo foo1(37);
Foo foo2(104);

我的问题是,我需要实现一个类,其中包含一个成员,它是一个3x6的数组。我应该如何做类似于上面的事情?

class Bar {
   int coeff[3][6];
public:
   // what do I do for a constructor????
};

编辑:对于一个普通的数组,我会按照以下方式操作,但我不知道如何处理类:

 static int myCoeffs[3][6] = 
 {{  1,  2,  3,  4,  5,  6}, 
  {  7,  8,  9, 10, 11, 12},
  { 13, 14, 15, 16, 17, 18}};

编辑2:由于某些原因(例如,这是一个带有限制的嵌入式系统),我不能使用Boost,因此如果它提供了解决方案,我无法使用它。


更新:我没有被绑定到初始化程序。可以在构造函数体中完成,也不必是内联的。我只是在寻找一种正确的方式来构造一个需要系数数组的类的实例,而不会弄乱指针分配或其他什么。


哪个版本的C++?如果您正在使用当前(C++03)标准的版本,则无法模拟初始化程序。 - Billy ONeal
“老派”的C++——这是为嵌入式系统设计的,我不知道使用哪个标准版本,甚至2003年的可能都太新了。 - Jason S
2003年是第一个标准化版本。 - Billy ONeal
6个回答

6

无法在C++03中使用构造函数初始化列表初始化数组。但是,您可以在构造函数体中执行此操作(从技术上讲,这不再是一种初始化)。

也就是说

struct x
{
    int a[4];
    x():a({1,2,3,4}) //illegal
    {
        a[0] = 1;
        etc. 
    }
};

编辑: 在问题编辑之后,这里提供一种实现的方式

#include <algorithm>
struct x
{
   int arr[3][4];
   x(int (&arg)[3][4])
   {
      std::copy(&arg[0][0], &arg[0][0]+3*4, &arr[0][0]);
   }

};

好的,那没关系,我只需要一种“好”的方法来做这件事。 - Jason S
@Jason:我能想到的唯一“好”的方法是在构造函数中逐个初始化它们,例如 a[0] = 1; a[1] = 23; 等等。 - Armen Tsirunyan
呸,烦死了。我想我只能传入一个数组,然后使用一对for循环来复制元素了。 - Jason S
@Billy:在C++03标准下不行。不确定在C++0x标准下会怎样。 - Armen Tsirunyan
int (&arg) 是什么鬼? - Jason S
显示剩余7条评论

2

我不知道这是否听起来太明显,但为什么不直接复制这些值呢?

class Foo {
    static const int X = 3;
    static const int Y = 6;

    int mCoeff[X][Y];

    void setCoeff(int coeff[X][Y]) {
        for (int i = 0; i < X; i++) {
            for (int j = 0; j < Y; j++) {
                mCoeff[i][j] = coeff[i][j];
            }
        }
    }
public:
    Foo(int coeff[X][Y]) {
        setCoeff(coeff);
    }

};

希望我的帮助对您有所帮助。祝一切顺利。

这个错误与我最初的答案犯了同样的错误。 - Billy ONeal
好的,所以我必须将 int coeff[X][Y] 更改为 int **pcoeff - Jason S
正如Jason建议的那样,我更改了方法签名,以便它可以接受动态分配的整数数组。这种方式不会检查数组边界,因此可能会出现分段违规故障。 - redent84
@Billy:真的吗?现在我很困惑 :/ - Jason S
@Billy:int[][] 是一块连续的内存块,而 int** 则是指向 int 指针的指针。它们可能表示相同的东西,即整数的二维数组。区别在于 int[][] 是连续的内存,而 int** 不是,因为它是动态分配的(使用 malloc(sizeof(int)*X) 或 new int[X])。 - redent84
显示剩余5条评论

1

在C或C++中,通常无法像Java那样将任意多维数组作为参数传递给函数(我提到Java是因为您的问题历史记录表明您的经验在Java方面)。

目前的标准确实没有支持类似于数组初始化器的东西,尽管在下一个版本C++0x中有一些计划来改变这种情况。

如果您希望具有像Java数组那样的灵活性(客户端可以更改指向数组的大小),则有几个选项。首先且最好的是使用std::vector<>,它为您实现了一个动态数组,但您可能会受到嵌入式平台的限制。您还可以自己实现单维数组,并接受动态内存块。例如:

class Foo
{
    int *theArray_;
    unsigned int rows_;
    unsigned int cols_;
public:
    Foo(int *theArray, int rows, int cols)
        : theArray_(theArray)
        , rows_(rows)
        , cols_(cols)
    { }
    void UseTheArray()
    {
        //Access array[5][6]
        theArray[5*cols+6];
    }
};

请注意,在这种情况下,被调用方负责处理内存。此外,考虑使用std::auto_ptr而不是原始指针,以明确谁负责在对象销毁时清除内存块。
还要注意,您不应该使用名称_x - 以下划线开头的名称有许多规则与它们相关,您可能希望避免考虑这些规则。
编辑:这是我的原始答案的一部分;它是错误的:
在C++中,多维数组只是一个单一的内存块。只有在类中预先知道数组的确切维度时,才能像这样接受多维数组。然后,您可以编写类似于以下内容的代码:
class Foo {
   int coeff[3][6];
public:
   Foo(int _x[3][6]) : coeff(_x) {}
};

请注意,数组的大小是固定的,不能由您类的客户端更改。

@Billy:这绝对是非法的!我向你保证!你传递的参数实际上是一个指向数组的指针,而不是一个二维数组! - Armen Tsirunyan
@Armen:嗯...我不明白为什么它不起作用。但显然它没有。该死!(有时我想知道为什么多维数组甚至存在于语言中!) - Billy ONeal
@Jason:哪一个?是@Armen指出错误的那个还是我最近列出的那个? - Billy ONeal
你们的工作速度比我快 :/ - Jason S
较近的更新应该可以工作,我只是不想在运行时进行指针数学计算。但构造函数的时间还可以。我确实每个实例都有一个固定大小的数组。老实说!否则我就得像你说的那样使用std::vector。(顺便说一句,似乎在SO中有一个bug,出于某种原因我不能投票,除非你再次编辑帖子。建议你将结尾处的“应该”改为“不应该”) - Jason S
显示剩余4条评论

1
在C++03中,由于您无法在初始化列表中初始化数组,因此您可以编写通用的函数模板来使用给定的数组填充数组,如下面的示例所示,
template<typename T, size_t N>
void array_fill(T (&dest)[N], T (&src)[N])
{
   for ( size_t i = 0 ; i < N ; i++ )
       dest[i] = src[i];
}
struct A
{
   int a[5];
   A(int (&i)[5]) { array_fill(a, i); }
   void print() 
   {
      for ( int i = 0 ; i < 5 ; i++ ) cout << a[i] << " ";
   }
};
int main() {
        int a[5] = {1,2,3,4,5};
        A obj(a);
        obj.print();
        return 0;
}

输出:

1 2 3 4 5

在 ideone 上运行:http://ideone.com/pFcrv

嗯,已经有std::copy可以使用了。


  1. 我会使用std::copy实现array_fill,因为在许多STL中,它将分解为对memcpy的调用,这可能在目标硬件上更快。
  2. 这对于OP的用例不起作用,因为他正在处理多维数组。
- Billy ONeal
@Billy:我也是这么想的。我太懒了,正在看电视,不想自己实现它 :D。这就是为什么我在最后一行提到了std::copyarray_fill可以优雅地编写以处理多维数组,而std::copy可能会有很大帮助! - Nawaz

-1
如果你必须这样做,我建议使用for循环迭代二维数组的元素并初始化它们。 或者,如果你想要更快的速度,可以使用memset等类似方法。
memset(&coeff,0,3*6*sizeof(int)) 

嗨,比利,抱歉,OP's 是什么意思? - Toni
1
原帖 / 原作者 - luke

-1
你可以这样做:
#include <algorithm>
class Bar 
{    
    int coeff[3][6]; 
public:    // what do I do for a constructor???? 
    Bar()
    {
        int myCoeffs[3][6] = 
        {
            {  1,  2,  3,  4,  5,  6},    
            {  7,  8,  9, 10, 11, 12},   
            { 13, 14, 15, 16, 17, 18}
        }; 
        std::swap(coeff, myCoeffs);
    }
};

为什么要交换?coeff = myCoeffs 有什么问题吗?但是这样做也无法解决 OP 的问题,因为您没有将参数传递到构造函数中。 - Billy ONeal
但我需要将系数传递给构造函数。否则,对象的每个实例都会获得相同的系数。 - Jason S
@Billy 我已经(可能太早了)完全吸收了移动语义 :) - Alain Rist

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接