初始化对象数组

19

我目前正在开发一款卡牌游戏,但是我在一些初始化代码方面遇到了问题:

// in my class...
Card cards[20];
// in method...
for(int i = 0; i <= 20;i++)
    cards++ = new Card(i, /*i as char +*/ "_Card.bmp");
我的编译器报错,指出cards++不是一个左值。我了解了指针和数组的等价性,并且我认为我已经理解了它,但是我无法让它工作。我的理解是,由于cards会降级为指针,而new运算符会给我返回一个指向Card新实例位置的指针,所以上面的代码应该可以编译通过,对吧?
我也尝试使用下标,但是cards+icards++cards[i]不就是三种说同一件事的方法吗?我认为它们都是左值并被视为指针。

1
cards+i 返回 cards+i;cards++ 将 cards 增加一;cards[i] 返回 cards 中第 i 个元素的引用。它们都不同。 - user142019
5个回答

25
Card cards[20];

cards已经是一个对象数组。它们使用默认构造函数(没有参数的构造函数)构建。不需要再次使用new。可能您需要一个等同于构造函数参数的成员函数,并通过它进行赋值。

for ( int i=0; i<20; ++i ) // array index shouldn't include 20
   cards[i].memberFunction(/*....*/);

更简单的方法是使用 std::vector

std::vector<Card> cards;
for( int i=0; i<20; ++i )
    cards.push_back(Card(i, /*i as char +*/ "_Card.bmp"); )

我想使用向量会是一个更好的主意。所以我尝试使用向量,但现在我遇到了很多次的问题:一旦我包含了<vector>,我就会从libcpmtd.lib得到一长串看起来疯狂的“未解决的外部”错误列表。这告诉我我的代码没有问题,但我仍然无法编译... 唉。 - Stephen Collins
1
如果您想使用std::vector并知道要添加的元素数量,请勿使用push_back:开销虽小但可避免。 您应该以正确的大小初始化向量'std::vector<Card> cards(20);',然后以与数组相同的方式初始化成员。 - Clodéric
2
@Clodéric,您也可以通过预分配向量来解决push_back的低效问题:std::vector<Card> cards; cards.reserve(20);。这使得您可以通过完美转发使用自定义构造函数参数来调用emplace_backcards.emplace_back(i, /*i as char +*/ "_Card.bmp");。这种方法似乎更易读/易维护,因为它使用构造函数而不是强制初始化方法。 - Jeff G

5
代码Card cards[20];已经创建了一个包含20个默认构造函数的Card对象的数组。鉴于您的代码,这可能不是您想要的结果。我建议使用vector代替。
std::vector<Card> cards;

for(int i = 0; i < 20;i++)
{
    cards.push_back(Card(i, /*i as char +*/ "_Card.bmp"));
}

请注意,您的for循环从020,因此超出了数组的末尾。

4

好的,还有一种可能,就是当您同意在初始化时自动调用构造函数时:

// in my class...
Card cards[20] = { Card(0, "0_Card.bmp"), Card(1, "1_Card.bmp"), /* ... */ };

巨大的缺点是在这种情况下无法使用循环。

4

如果想要避免不必要的构造函数调用和不必要的重新分配空间,那就比较复杂了,因为 C++ 通常按照分配顺序逐个初始化每个对象。其中一个解决方法是采用 Java 的方式 -- 使用循环和指针数组,例如:

Card *cards[20];
for (int i=0; i<20; i++) {
  cards[i] = new Card(i);
}

另一种选择是使用malloc来获取显式未初始化的内存:
Card *cards = malloc(20 * sizeof(Card));
for (int i=0; i<20; i++) {
  new (&(cards[i])) Card(i);
}

1
在你的代码中,数组名称cards包含了数组第一个元素的地址。这些地址在运行时分配,您无法更改它们。因此编译器会抱怨cards不是左值。
但是您可以通过使用指针来明确指定这些地址可以保存什么,如下所示:
// in my class...
Card cards[20];

Card *cardsPointer = cards;// Pointer contains the address of the
//1st element of 'cards' array.

// in method...
for(int i = 0; i < 20; i++)
*(cardsPointer++) = Card(i, /*i as char +*/ "_Card.bmp");// Note that 
// there is no 'new' operator as 'cardsPointer' has type 'Card *' and 
// not 'Card **'. And 'cardsPointer' has type 'Card *' as the array is
// of type 'Card'.

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