在循环中初始化预分配的结构体实例

initializing pre-allocated struct instances within a loop

本文关键字:结构体 实例 预分配 初始化 循环      更新时间:2023-10-16

我想使用malloc()为特定结构的特定数量的实例分配内存。然后,我想在循环中初始化每个实例。但是,对于每次迭代,我观察到构造函数和之后的析构函数都被调用……为什么?更让我惊讶的是,尽管调用了析构函数,但我的每个实例都在循环之后存在……我的实例初始化为相同的值!我肯定错过了一些重要的东西……如果有人能帮助我,我会很感激,因为现在,我无法解释发生了什么。下面是我的c++代码:

struct myStruct{
   int* a;
   int* b;
   myStruct(int x, int y)
   {
    std::cout << "the constructor is called" << std::endl;
    a = (int*)malloc(x*sizeof(int));
    b = (int*)malloc(y*sizeof(float));
   }
   ~myStruct()
   {
       std::cout << "the destructor is called" << std::endl;
       delete[] a;
       delete[] b;
   } };
int main(int argc, char** argv){
int Nb = 3;
myStruct *S = (myStruct*)malloc(Nb*sizeof(myStruct));
for(int i=0 ; i<Nb ; i++)
{
    *(S+i) = myStruct(1,2);
}
std::cout << std::endl;
for(int i=0 ; i<Nb ; i++)
{
    std::cout << "instance " << i << " :" << std::endl;
    std::cout << (unsigned int)(*(S+i)->a) << std::endl;
    std::cout << (unsigned int)(*(S+i)->b) << std::endl << std::endl;
}
system("PAUSE");}

命令窗口显示:

构造函数被称为

析构函数被称为

构造函数被称为

析构函数被称为

构造函数被称为

析构函数被称为

实例0:16085247124277075694

实例1:16085247124277075694

实例2:16085247124277075694

按任意键继续…

在表达式

*(S+i) = myStruct(1,2)

所发生的是,您创建了一个临时实例的结构(myStruct(1,2)部分),然后复制该实例到S[i]。复制是浅层的,因此只复制指针,不分配或复制新数据。表达式完成后,临时实例就不再需要了,因此它被销毁了。

这种销毁当然会导致释放数据成员,因此数组(副本)结构体中的指针不再有效,访问它们是未定义的行为。而且,你实际上并没有将分配的内存初始化为任何东西,因此内存将包含分配之前在那里的任何内容,并且内容看起来是随机的。

我建议你读一下std::vector, std::shared_ptr,最重要的是三法则。

每次通过循环,代码都会创建一个临时对象(myStruct(1,2)),然后销毁它。这就是输出显示的内容。

这个临时对象被赋值给未初始化的对象*(S+i),这不是一件好事。对象应该由构造函数初始化,而不是赋值操作符。这里使用构造函数的方法是放置new:

new (S+i) myStruct(1,2);

括号内的第一个值是要构造对象的地址。

这样做之后,正如其他人提到的,您不能在结果数组上使用delete,因为它不是用new创建的。因此,您必须循环遍历对象并显式地调用每个对象的析构函数,然后free内存。