-2

我对以下说明感到非常困惑:

#include <iostream>
#define MAX_IT 100
using namespace std;

class Integer{

private :
    int a;
public:
    Integer(int valoare){a=valoare;}
    int getA(){return a;}
    void setA(int valoare){a=valoare;}
};

int main(){
    Integer* a=new Integer(0);

    //cout<<a[0].getA();
    for(int i=1;i<=MAX_IT;i++)
    {
        a[i]=*(new Integer(i));
    }

    for(int i=0;i<=MAX_IT;i++)
        cout<<a[i].getA()<<endl;

    return 13;
}

它适用于 MAX_IT 的小值,但是当我尝试将 MAX_IT 设置为 1000 时,它不再起作用。最初,我认为“新”运算符应该完成这项工作,但在阅读了一些文档后,我了解到它根本不应该像这样工作(超出范围的数组)。

所以我的问题是:为什么它适用于 MAX_IT 的小值而不适用于较大的值?

编辑:

我正在为一个更大的程序试验这段代码,我不允许使用 STL。你没有理解我的担心:如果我有 Integer *var=new Integer[10]; for(int k=1;K<10;k++) *(var+k)=k; //这很好,但如果我尝试 var[10]=new Integer; //这不应该工作,应该会产生一个内存问题 //我担心的是,如果我只做 100 次左右它就可以工作......问题是为什么它每次都在少量迭代中工作?

4

3 回答 3

17

因为通过为one Integer分配空间然后将其用作多个Integers 的数组,您的代码会调用未定义的行为,这意味着它可以做任何事情,包括崩溃、看似正常的工作或将恶魔从鼻子里拉出来。


无论如何,它正在泄漏内存。如果您不需要动态内存分配,请不要使用它。

a[i]=*(new Integer(i));

而且kaboom,您丢失了指向 的指针Integer,以后再也没有机会了delete。泄漏。


如果您不需要原始数组,请不要使用它们。更喜欢std::vector. 如果 C++ 太难,或者切换到 C。

std::vector<Integer> vec;
vec.push_back(Integer(1337));
于 2013-06-17T21:31:14.223 回答
2

当您稍微溢出缓冲区时,事情往往会很好地工作的原因是......内存碎片!谁会猜到?

为避免内存碎片,分配器不会返回一个sizeof (Integer). 他们会给你一个更大的块,以确保如果该块稍后在相邻块之前被释放,它至少足够大以便有用。

确切的大小可能会因架构、操作系统、编译器版本甚至机器中物理存在的内存量而异。你应该认为它是完全不可预测的。此外,一些旨在帮助捕获此类错误的库会强制将任何小对象放置在块的末尾而不是开头,因此额外的字节可能是负数组索引而不是正数。

因此,永远不要依赖于在对象之后(或之前)免费为您提供空闲区域。


大师注:偶尔有人想出一个有效的额外内存用途,并要求一种方法来发现它有多大。一个很好的例子是std::vector可以调整 a 的容量(不是大小!)以匹配实际分配的空间而不是请求的空间,从而减少(平均)所需的重新分配次数。此类请求通常与其他 guru 分配器 API 配对使用,例如,如果碰巧相邻有空闲块,则能够就地扩展分配。


请注意,在您的特定情况下,您仍然有未定义的行为,因为您正在调用operator=尚未首先构造的非 POD 对象。如果你给出了class Integer一个会改变的微不足道的默认构造函数。

于 2013-06-17T22:00:03.330 回答
0

你实际上需要

Integer* a=new Integer[MAX_IT];

//cout<<a[0].getA();
for(int i=1;i<MAX_IT;i++) << note < not <=
{
    a[i]=i;
}

更好的是使用 std::vector

于 2013-06-17T21:39:11.670 回答