为什么我的课'当我向向量添加实例时,会调用s析构函数
Why does my class's destructor get called when I add instances to a vector?
似乎每次向向量m_test添加对象时,都会调用析构函数方法。我是不是错过了什么?我该如何防止这种情况发生?
class TEST
{
public:
TEST();
~TEST();
int * x;
};
TEST::TEST()
{
}
TEST::~TEST()
{
... it is called every time I push_back something to the vector ...
delete x;
}
vector<TEST> m_test;
for (unsigned int i=0; i<5; i++)
{
m_test.push_back(TEST());
}
这里的问题是你违反了三条规则。你的类有一个析构函数,所以你也需要一个复制构造函数和一个赋值运算符。或者,您不能允许复制您的类(例如,通过使T(T const&)
和T& operator=(T const&)
私有,或者通过从boost::noncopyable
派生),然后调整向量的大小,而不是使用push_back
。
在第一种情况下,您可以像往常一样只push_back
您的类。在第二种情况下,语法将类似于
std::vector<TEST> vec(5);
// vec now has five default-constructed elements of type TEST.
不做这两件事都是个坏主意,因为你很可能在某个时候遇到双重删除问题——即使你认为你永远不会在x != nullptr
的位置复制或分配TEST
,明确禁止它也要安全得多
顺便说一句,如果您有成员指针,当对象超出范围时应该删除,请考虑使用智能指针,如scoped_ptr
、unique_ptr
和shared_ptr
(如果您无法使用Boost或C++11,则可能使用auto_ptr
)。
当您push_back
时,它不被调用,当临时文件被销毁时,它被调用。
在您的示例中修复它:
TEST test;
for (int i = 0; i < 5; ++i)
{
m_test.push_back(test);
}
应该只调用一次。
您的代码正在循环中创建一个临时的TEST
,并在push_back
中使用它,然后当循环结束/重复并被销毁时,该临时的就超出了作用域。由于临时TEST
需要清理,所以这种情况完全应该发生。
如果你想避免这种情况,你需要做任何其他事情,但每次推都要做一个临时对象。一个潜在的解决方案是:
vector<TEST> m_test(5); // Note reserving space in the vector for 5 objects
std::fill(m_test.begin(), m_test.end(), TEST()); // Fill the vector with the default ctor
根据STL的优化方式,这可能不需要制作多个副本。
如果您在TEST
类中实现一个复制构造函数,比如:,您也可以得到更好的处理
TEST::TEST(const TEST & other)
{
x = new int(*other.x); // Not entirely safe, but the simplest copy ctor for this example.
}
这是否合适,或者你如何处理它,取决于你的类及其需求,但当你定义了自己的常规构造函数和析构函数时,你通常应该有一个复制构造函数(否则编译器会生成一个,在这种情况下,它会导致复制和挂起指向x
的指针)。
若要避免销毁临时和以避免复制构造函数,请考虑使用vector::resize或vector::template_back。下面是一个使用emplace_back
:的示例
vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ )
{
m_test.emplace_back();
}
矢量元素将在不需要复制的情况下就地构建。当vt被销毁时,每个向量元素都会自动销毁。
需要c++0x(将-std=c++0x
与gnu一起使用)。CCD_ 20当然也是必需的。
如果没有使用默认构造函数(例如,如果TEST::x
是引用而不是指针),只需在对emplace_back()
的调用中添加自变量,如下所示:
class TEST
{
public:
TEST( int & arg) : x(arg) {;} // no default constructor
int & x; // reference instead of a pointer.
};
. . .
int someInt;
vector<TEST> m_test;
m_test.reserve(5);
for ( uint i=0; i<5; i++ ) {
m_test.emplace_back( someInt ); // TEST constructor args added here.
}
所示的CCD_ 23是可选的,但确保在开始构建向量元素之前有足够的空间可用。
vector.push_back()
将给定对象复制到其存储区域中。您在push_back()
调用中构建的临时对象在被复制后立即被销毁,这就是您所看到的。某些编译器可能能够优化此副本,但您的编译器显然不能。
在m_test.push_back(TEST());
中,TEST()将创建一个临时变量。向量将其复制到自己的内存后,临时变量将被销毁。
你可以这样做:
vector<TEST> m_test(5, TEST());
析构函数不仅仅是为临时变量调用的。
当向量的容量发生变化时,也会调用析构函数。
这种情况经常发生在非常小的向量上,而在大向量上则不太常见。
这导致:
新的内存分配(大小基于增长指标,而不仅仅是大小+1)
将旧元素复制到新分配中
破坏旧矢量中的元素
释放旧的矢量内存
将新项的构造复制到新向量的末尾。
请参阅此处的第三个答案:当我将_返回到向量时调用析构函数
- 在C++中将类实例添加到对象层次结构中的问题
- 为什么自删除的全局 Vulkan 实例仅在添加层时才导致段错误?
- 将内存文件添加到 clang 编译器实例
- 我可以将一个套接字添加到多个 epoll 实例吗?
- 添加无模板实例化的访问者方法
- 对成员变量的引用在向同一向量中添加另一个实例后断开
- 将类的每个实例添加到列表对象的构造函数
- 创建 QQuickItem 子类的实例是否有问题,我不打算渲染或添加到 QML 树中的实例?
- 将类的实例传递给另一个构造函数,该构造函数将其对象添加到所传递实例所拥有的列表中
- C 将条目添加到具有字符串和类实例的STL映射中,作为指针
- 将类C++实例转换为 NSObject,然后添加到 NSMutableArray
- 将从接口派生的类的实例添加到接口指针数组中
- 一个非内联非虚拟方法向类的实例添加了多少字节?C++
- 为什么我的课'当我向向量添加实例时,会调用s析构函数
- 在 C++ 中将"this"添加到类实例化的向量
- 将解码实例添加到可以调用主类的类中
- 使用MSXML 6.0向SAXXMLReader60实例添加模式集合
- 优雅地重用将const添加到类实例化中的代码
- 如何将预先确定的模板实例化集添加到函数模板中
- 如何在不'new'的情况下将新的对象实例添加到 std::list