5

我在这里遇到了一些困难的情况,我希望有人能帮助我。

我有以下,

struct CandyBar{ 
  std::string name; 
  double weight; 
  int calories; 
} ;

现在,创建一个包含许多 CandyBar 的结构数组非常简单,就像我所做的那样;

int main(){
   CandyBar bars[] = {{"Mango tart", 2.3, 100}, {"Yo Yo", 3.2, 130}, {"Orange Ball", 1.7, 98}};
  return 0;
}

但是,现在我想使用 new 创建相同的结构。当我想到它时这很简单,但这会崩溃并且不起作用。

CandyBar *bars = new CandyBar;
  (*bars).name = "Mango tart";
   bars->weight =  2.3;
   bars->calories =  100;
   bars += 1;

  (*bars).name = "Yo Yo";
  bars->weight =  3.2;
  bars->calories =  130;

  bars += 1;
  (*bars).name =  "Orange Ball";
  bars->weight =  1.7;
  bars->calories =  98; 

但是,这不起作用。因为我认为第一个指针是指向第一个结构的内存位置,然后我创建结构,然后使用 bar += 1 增加地址,然后继续创建指针,但我错过了一些非常严重的东西。

我将衷心感谢您的帮助。

4

4 回答 4

15

在您的第二个示例中,您只分配了一个CandyBar结构,但您将其视为一个数组。这不会很好地结束,并且是缓冲区溢出的秘诀。

为了分配 的数组CandyBars,您需要告诉 new 您想要一个数组,如下所示:

CandyBar* bars = new CandyBar[3];

确保在删除数组时CandyBars,您正在使用数组删除,如下所示:

delete[] bars;

综上所述,在 C++ 生产代码中,您通常会使用 std::vector 或 std::array 来处理这种情况,因为在这种特殊情况下,您不必处理尽可能多的资源管理。

如果你必须在堆上动态分配一个数组并且仍然使用 RAII,我也会看看boost::shared_arrayboost::scoped_array.

于 2013-01-01T22:10:32.523 回答
6

仅为 one 分配空间CandyBar,因此您正在写入未分配的堆内存。这是一个很大的禁忌。您实际上很幸运它失败了,因为它具有产生非常难以调试的问题的能力。

CandyBar您可以像这样为更多 s分配空间:

CandyBar *bars = new CandyBar[3]; // 3 CandyBars.

...并且不要忘记像这样使用数组删除器:

delete[] bars;

但是,仍然有能力超出CandyBar您分配的 s 数量。在 C++ 中执行此操作的首选方法是使用std::vector.

在这个例子中,我给出CandyBar了一个简写的构造函数并将它们放入一个std::vector.

#include <string>
#include <vector>

struct CandyBar{ 
  std::string name;
  double weight;
  int calories;
  CandyBar(std::string name, double weight, int calories)
  {
      this->name = name;
      this->weight = weight;
      this->calories = calories;
  }
};

int main()
{
    std::vector<CandyBar> bars;
    bars.push_back(CandyBar("Mango tart", 2.3, 100));
    bars.push_back(CandyBar("Yo Yo", 3.2, 130));
    bars.push_back(CandyBar("Orange Ball", 1.7, 98));

    return 0;
}

没有new,没有delete,没有泄漏,没有腐败。

我还要补充一点,如果您使用的是具有某些 C++11 支持的编译器并且不想要std::vector为您提供的动态分配,您可以考虑std::array改用。

于 2013-01-01T22:25:08.690 回答
1

Foo * a = new Foo为 的一个实例分配空间Foo。如果要分配 的数组Foo,则需要使用Foo * a = new Foo[ARRAY_LEN].


基本上,您真正想要做的是动态分配一些内存来保存对象数组,在您的情况下为CandyBar对象。问题是,您正在使用new运算符,它只为一个这样的对象分配内存。然后,您尝试使用返回的内存地址,就好像它指向一个数组一样。您将不可避免地尝试访问尚未分配的内存,这将导致分段错误(充其量)。

您真正要查找的运算符是new[]运算符(调用为new CandyBar[ARRAY_LEN]),它为指定数量的对象的数组分配足够的内存。然后,您可以获取返回的内存地址并将其视为您提供的大小的数组,而不必担心超出内存分配。

通常,如果您要处理的CandyBars 集合在程序的整个生命周期中可能会增长或缩小,那么分配固定大小的数组不是可行的方法。看看std::vectorC++ STL 中的模板类 - astd::vector<CandyBar>可以根据CandyBar您要存储的 s 数量动态增长或缩小,并且可以像数组一样自由访问(例如 as foo[42])。

于 2013-01-01T22:09:41.590 回答
0

您应该分配一个数组CandyBarwith :

CandyBar *bars = new CandyBar[20];

然后您使用bars[0], bars[1]...bars[19]等来访问各个直板。

请注意,您的代码向指针bars + 1添加了一个sizeof CandyBar,但这指向一个未分配的区域(因为您刚刚分配了一个 CandyBar)。因此你的代码崩溃了。

于 2013-01-01T22:09:49.433 回答