C++ C++;具有动态分配的字符数组的结构
我试图将结构存储在向量中。Struct需要为给定大小的char*动态分配内存。 但一旦我将结构添加到向量,它的析构函数就会被调用,就像我丢失了指向它的指针一样 为了举例,我制作了这个小演示C++ C++;具有动态分配的字符数组的结构,c++,memory-management,struct,dynamic,destructor,C++,Memory Management,Struct,Dynamic,Destructor,我试图将结构存储在向量中。Struct需要为给定大小的char*动态分配内存。 但一旦我将结构添加到向量,它的析构函数就会被调用,就像我丢失了指向它的指针一样 为了举例,我制作了这个小演示 #include "stdafx.h" #include <iostream> #include <vector> struct Classroom { char* chairs; Classroom() {} // default constructor
#include "stdafx.h"
#include <iostream>
#include <vector>
struct Classroom
{
char* chairs;
Classroom() {} // default constructor
Classroom(size_t size)
{
std::cout << "Creating " << size << " chairs in a classroom" << std::endl;
chairs = new char[size];
}
~Classroom()
{
std::cout << "Destroyng chairs in a classroom" << std::endl;
delete[] chairs;
}
};
std::vector<Classroom> m_classrooms;
int main()
{
m_classrooms.push_back(Classroom(29));
//m_classrooms.push_back(Classroom(30));
//m_classrooms.push_back(Classroom(30));
system("Pause");
return 0;
}
是的,似乎析构函数被调用了两次!一次添加到向量,第二次在程序完成其执行时
当我尝试使用类而不是结构时,也会发生完全相同的情况
有人能解释为什么会发生这种情况,以及正确完成任务的可能方法吗?@LPVOID
使用emplace_back(..)在适当位置创建对象可以帮助您避免此处面临的双重释放或损坏错误
m_教室。向后安置(29)
但是,更好的做法是始终遵循3/5/0规则,以避免指针悬空结束 @LPVOID
使用emplace_back(..)在适当位置创建对象可以帮助您避免此处面临的双重释放或损坏错误
m_教室。向后安置(29)
但是,更好的做法是始终遵循3/5/0规则,以避免指针悬空结束 教室
类不能在std::vector
中安全使用,因为它的复制语义不正确。std::vector
将复制对象,如果复制语义有bug,那么当您开始在容器(如vector
)中使用该类时,您将看到所有这些bug都表现出来
为了使您的类具有正确的复制语义,它需要能够无错误地构造、分配和销毁自身的副本(这些错误包括内存泄漏、对同一指针的双重删除调用等)
代码中缺少的另一件事是类中需要知道size
参数。现在,您发布的只是内存分配,但是没有任何东西可以保存大小。如果不知道分配了多少个字符,就不可能正确实现用户定义的复制构造函数和赋值运算符,除非char*
是以空结尾的字符串
话虽如此,有多种方法可以修复您的类。最简单的方法是简单地使用内置了正确复制语义的类型,而不是自己处理原始内存。这些类包括std::vector
和std::string
。它们不仅自己清理,而且这些类知道自己的大小,而不必携带size
成员变量
struct Classroom
{
std::vector<char> chairs;
Classroom() {} // default constructor
Classroom(size_t size) : chairs(size)
{
std::cout << "Creating " << size << " chairs in a classroom" << std::endl;
}
};
注意初始化类的成员时成员初始化列表的用法。还要注意在实现赋值运算符时的用法
纠正的另一个问题是默认构造函数没有初始化所有成员。因此,在原始类中,可以使用简单的单行程序,例如:
int main()
{
Classroom cr;
}
会导致问题,因为在析构函数中,您会删除未初始化的指针
在此之后,std::vector
现在应该能够安全地使用。教室
类不能在std::vector
中安全地使用,因为它具有不正确的复制语义。std::vector
将复制对象,如果复制语义有bug,那么当您开始在容器(如vector
)中使用该类时,您将看到所有这些bug都表现出来
为了使您的类具有正确的复制语义,它需要能够无错误地构造、分配和销毁自身的副本(这些错误包括内存泄漏、对同一指针的双重删除调用等)
代码中缺少的另一件事是类中需要知道size
参数。现在,您发布的只是内存分配,但是没有任何东西可以保存大小。如果不知道分配了多少个字符,就不可能正确实现用户定义的复制构造函数和赋值运算符,除非char*
是以空结尾的字符串
话虽如此,有多种方法可以修复您的类。最简单的方法是简单地使用内置了正确复制语义的类型,而不是自己处理原始内存。这些类包括std::vector
和std::string
。它们不仅自己清理,而且这些类知道自己的大小,而不必携带size
成员变量
struct Classroom
{
std::vector<char> chairs;
Classroom() {} // default constructor
Classroom(size_t size) : chairs(size)
{
std::cout << "Creating " << size << " chairs in a classroom" << std::endl;
}
};
注意初始化类的成员时成员初始化列表的用法。还要注意在实现赋值运算符时的用法
纠正的另一个问题是默认构造函数没有初始化所有成员。因此,在原始类中,可以使用简单的单行程序,例如:
int main()
{
Classroom cr;
}
会导致问题,因为在析构函数中,您会删除未初始化的指针
在此之后,现在应该可以安全地使用std::vector
。是否需要使用char*
std::string
是字符串数据的正常选择,只起作用™ 在管理内存方面,您需要提供一个复制构造函数,它实际复制成员指向的数据;否则,push_back
调用(调用默认副本)只会复制指针。然后,当任何这样的副本被销毁时,指针将失效。请参阅。@chris我使用的是char*
,因为我需要存储原始字节std::vector