C ++ New vs Malloc用于对象的动态内存数组

时间:2012-03-14 15:00:39

标签: c++ visual-c++ malloc new-operator dynamic-memory-allocation

我有一个类子弹,它的构造有几个参数。但是,我使用动态内存阵列来存储它们。我正在使用C ++,所以我想通过使用new运算符来分配内存来符合它的标准。问题是新的运算符在我分配数组时要求构造函数参数,这是我当时没有的。我可以使用malloc来获得正确的大小,然后在那里填写表单,但这不是我想要使用的:)任何想法?

pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments

感谢。

6 个答案:

答案 0 :(得分:5)

你不能。

如果你真的想要符合C ++标准,你应该使用std::vector

仅供参考,它可能比你想要实现的成本更高。如果你这样做,new会调用一个构造函数。但是既然你以后会修改对象,那么初始构造就没用了。

答案 1 :(得分:5)

1)std::vector

std::vector确实是正确的C ++方法。

std::vector<Bullet> bullets;
bullets.reserve(10); // allocate memory for bullets without constructing any

bullets.push_back(Bullet(10.2,"Bang")); // put a Bullet in the vector.
bullets.emplace_back(10.2,"Bang"); // (C++11 only) construct a Bullet in the vector without copying. 

2)new []运算符

也可以使用new执行此操作,但实际上不应该这样做。使用new / delete手动管理资源是一项高级任务,类似于模板元编程,因为它最好留给库构建者,他们将使用这些功能为您构建高效的高级库。事实上,为了正确地执行此操作,您基本上将实现std::vector

的内部

使用new运算符分配数组时,数组中的每个元素都是默认初始化的。如果您向Bullet添加了默认构造函数,那么您的代码可以正常工作:

class Bullet {
public:
    Bullet() {} // default constructor
    Bullet(double,std::string const &) {}
};

std::unique_ptr<Bullet[]> b = new Bullet[10]; // default construct 10 bullets

然后,当您拥有Bullet的实际数据时,可以将其分配给数组的其中一个元素:

b[3] = Bullet(20.3,"Bang");

注意使用unique_ptr来确保正确清理,并且它是异常安全的。手动执行这些操作很困难且容易出错。


3)operator new

new运算符除了为它们分配空间外,还初始化其对象。如果您只想简单地分配空间,可以使用operator new

std::unique_ptr<Bullet,void(*)(Bullet*)> bullets(
    static_cast<Bullet*>(::operator new(10 * sizeof(Bullet))),
    [](Bullet *b){::operator delete(b);});

(注意unique_ptr确保存储将被释放但不再存在。具体来说,如果我们在此存储中构造任何对象,我们必须手动销毁它们并以异常安全的方式执行此操作。)< / p>

bullets现在指向足以存储Bullet个数组的存储空间。您可以在此存储中构建一个数组:

new (bullets.get()) Bullet[10];

然而,数组结构再次使用每个元素的默认初始化,我们试图避免这种情况。

AFAIK C ++没有指定任何定义良好的构造数组的方法而不构造元素。我想这很大程度上是因为这样做对于大多数(全部?)C ++实现来说都是无操作的。因此,虽然以下技术上未定义,但在实践中它的定义非常明确。

bool constructed[10] = {}; // a place to mark which elements are constructed

// construct some elements of the array
for(int i=0;i<10;i+=2) {
    try {
        // pretend bullets points to the first element of a valid array. Otherwise 'bullets.get()+i' is undefined
        new (bullets.get()+i) Bullet(10.2,"Bang");
        constructed = true;
    } catch(...) {}
}

这将构造数组的元素而不使用默认构造函数。您不必构造每个元素,只需要构建您想要使用的元素。然而,当破坏元素时,你必须记住只破坏构造的元素。

// destruct the elements of the array that we constructed before
for(int i=0;i<10;++i) {
    if(constructed[i]) {
        bullets[i].~Bullet();
    }
}

// unique_ptr destructor will take care of deallocating the storage 

以上是一个非常简单的案例。如果不将这些方法全部包含在类中,则可以非常轻松地使用此方法异常安全。将它包装在一个类中基本上相当于实现std::vector


4)std::vector

所以只需使用std::vector

答案 2 :(得分:1)

可能做你想做的事 - 如果你真的想知道如何,搜索“operator new”。但这几乎肯定是一个坏主意。相反,使用std :: vector,它将为您处理所有恼人的细节。您可以使用std :: vector :: reserve来提前分配您将使用的所有内存。

答案 3 :(得分:0)

Bullet** pBulletArray = new Bullet*[iBulletArraySize];

然后填充pBulletArray:

for(int i = 0; i < iBulletArraySize; i++)
{
   pBulletArray[i] = new Bullet(arg0, arg1);
}

不要忘记随后使用删除释放内存。

答案 4 :(得分:0)

C ++ new正常工作的方式是为类实例分配内存,然后调用该实例的构造函数。你基本上已经为你的实例分配了内存。

您只能调用第一个实例的构造函数,如下所示:

new((void*)pBulletArray) Bullet(int foo);

调用第二个的构造函数看起来像这样(等等)

new((void*)pBulletArray+1) Bullet(int bar);

如果Bullet构造函数采用int。

答案 5 :(得分:0)

如果你真正想要的只是快速分配/解除分配,那么你应该研究“内存池”。我建议使用boost's implementation,而不是尝试自己动手。特别是,您可能希望使用“object_pool”。