我有一个类子弹,它的构造有几个参数。但是,我使用动态内存阵列来存储它们。我正在使用C ++,所以我想通过使用new运算符来分配内存来符合它的标准。问题是新的运算符在我分配数组时要求构造函数参数,这是我当时没有的。我可以使用malloc来获得正确的大小,然后在那里填写表单,但这不是我想要使用的:)任何想法?
pBulletArray = (Bullet*) malloc(iBulletArraySize * sizeof(Bullet)); // Works
pBulletArray = new Bullet[iBulletArraySize]; // Requires constructor arguments
感谢。
答案 0 :(得分:5)
你不能。
如果你真的想要符合C ++标准,你应该使用std::vector
。
仅供参考,它可能比你想要实现的成本更高。如果你这样做,new
会调用一个构造函数。但是既然你以后会修改对象,那么初始构造就没用了。
答案 1 :(得分:5)
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.
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
来确保正确清理,并且它是异常安全的。手动执行这些操作很困难且容易出错。
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
。
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”。